import base64
import calendar
import copy
import datetime
import json
import logging
import re
import time
import uuid
from decimal import Decimal
from hashlib import md5

import pymongo
import requests
from pymysql import connect
from qcloud_cos import CosConfig, CosS3Client
from sqlalchemy import and_, extract, func, or_
from tornado import httpclient
from tornado.escape import json_encode
from tornado.httpclient import HTTPRequest
from tornado.httputil import url_concat

from base.connection import mongodb_util, redis_util
from base.request import ApiBaseHandler
from common.definition import (
    OrderStatus,
    OrderType,
    PayStatus,
    PayType,
    ret_msg,
)
from conf import config, promotion
from conf.config import (
    CANCEL_PAID_ORDER_IS_NEED_CHECK,
    DAYS_AFTER_RECEIVED_FOR_AUTO_COMPLETION,
    DAYS_AFTER_SHIPPED_FOR_AUTO_COMPLETION,
    FACTORY_UID,
    GIFT_ORDER_REFUND_TIMEOUT,
    MP_APP_ID,
    TI_YAN_GOODS_ID,
    KUAIDI100_CUSTOMER,
)
from conf.config import DOMAIN, HOST_NAME
from daemon import tasks
from helper import order, store
from helper.api_helper import ApiHelper
from helper.beanstalkd import add_mq_task
from helper.coupon_helper import get_available_coupons
from helper.express_helper import ExpressHelper
from helper.gift import GiftHelper
from helper.payment.balance import BalanceHandler, create_balance_record
from helper.payment.pay_util import (
    calculate_order_fee,
    generator_trade_no,
    get_red_packet,
)
from helper.payment.refund import cancel_order_immediate_refund
from helper.payment.wechat_base import Wechat_Base
from helper.payment.wechat_pay import WechatPay
from helper.user import AddressHelper, UserHelper
from util.json_util import JSONEncoder
from util.str_util import replace_emoji

logger = logging.getLogger(__name__)


class UserAddress(ApiBaseHandler):
    def create_agency(self, open_id, inviter_oid, name, mobile):
        """
        创建合伙人账号
        """

        class User(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user_agency", "model": UserAgency},
            ]
        )

        user_agency = (
            session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()
        )

        if user_agency:
            # 如果用户已经是合伙人，直接返回
            session.commit()
            session.close()
            return 0
        else:
            # 普通用户注册合伙人账号
            user = session.query(User).filter_by(ebf_user_id=open_id).first()
            recommend_user = user.ebf_user_recommend_user
            if (
                recommend_user
                and inviter_oid != open_id
                and recommend_user != inviter_oid
            ):
                user.ebf_user_recommend_user = inviter_oid  # 更新用户推荐人为邀请人
                session.commit()
                recommend_user = inviter_oid

            invite_user = (
                session.query(User).filter_by(ebf_user_id=recommend_user).first()
            )

            if not invite_user:
                logger.error(f"邀请人不存在: open_id={open_id}, inviter_oid={inviter_oid}")
                session.close()
                return 1

            uid = invite_user.ebf_user_agency_uid
            agency_uid = str(uuid.uuid1())
            password = "style999"
            md5_obj = md5()
            md5_obj.update(password.encode("utf-8"))
            pwd = md5_obj.hexdigest()

            # if user.ebf_user_agency_uid == config.DEFAULT_AGENCY_UID and uid != config.DEFAULT_AGENCY_UID:
            #     parent_uid = uid  # 在用户所属合伙人为默认合伙人的情况下变更上级为邀请人
            # else:
            #     parent_uid = user.ebf_user_agency_uid  # 否则上级设置为用户所属合伙人
            parent_uid = uid  # 新合伙人上级修改为邀请人 - 20201031

            parent_agency = (
                session.query(Agency).filter_by(ebf_agency_uid=parent_uid).first()
            )
            parent_agency_id = (
                parent_agency.ebf_agency_id
                if parent_agency
                else config.DEFAULT_AGENCY_ID
            )
            depth = parent_agency.ebf_agency_depth + 1 if parent_agency else 1
            career_agency = UserHelper.get_career_agency(parent_uid)
            career_agency_uid = (
                career_agency.ebf_agency_uid
                if career_agency
                else config.DEFAULT_AGENCY_UID
            )

            try:
                # 创建合伙人账户
                _agency = Agency()
                _agency.ebf_agency_name = name
                _agency.ebf_agency_uid = agency_uid
                _agency.ebf_agency_contact = mobile
                _agency.ebf_factory_id = config.FACTORY_ID
                _agency.ebf_agency_parent_id = parent_agency_id
                _agency.ebf_agency_type = 0
                _agency.ebf_agency_sub_type = 0
                _agency.ebf_agency_invite_uid = parent_uid if parent_uid else None
                _agency.ebf_agency_depth = depth
                _agency.ebf_agency_career_uid = career_agency_uid
                session.add(_agency)
                session.flush()  # 此处flush()不能省略

                # 创建合伙人后台登录账号
                agency_id = _agency.ebf_agency_id
                id = str(_agency.ebf_agency_id)
                new_user = User()
                new_user.ebf_user_id = "P" + id
                new_user.ebf_user_password = pwd
                new_user.user_create_date = datetime.datetime.utcnow()
                new_user.ebf_user_phone = mobile
                new_user.ebf_user_nickname = user.ebf_user_nickname
                new_user.ebf_user_factory_id = config.FACTORY_ID
                new_user.ebf_user_type = 3
                new_user.ebf_user_account = "P" + mobile
                new_user.ebf_user_gender = user.ebf_user_gender
                user.ebf_user_agency_uid = agency_uid
                user.ebf_user_phone = mobile
                session.add(new_user)
                session.flush()  # 此处flush()不能省略

                # 绑定合伙人微信和登录账号
                _user_agency = UserAgency()
                _user_agency.ebf_user_id = "P" + id
                _user_agency.ebf_agency_id = _agency.ebf_agency_id
                _user_agency.ebf_ua_bind_user_id = open_id
                session.add(_user_agency)
                session.commit()
                session.close()
                tasks.agency_registered.delay(agency_id)
                return 0
            except Exception as e:
                logging.error(e)
                session.rollback()
                session.close()
                return -1

    async def register(self, open_id, inviter_oid):
        class User(object):
            pass

        session = self.get_db_session([{"db_table": "ebt_user", "model": User}])
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        invite_user = session.query(User).filter_by(ebf_user_id=inviter_oid).first()
        if not invite_user:
            logger.error("邀请人不存在: oid=%s, inviter_oid=%s" % (open_id, inviter_oid))
            session.close()
            return False

        if not user:
            uid = invite_user.ebf_user_agency_uid
            user = await self.create_user(open_id, uid, inviter_oid)

        session.close()
        return True

    def create_order(self, open_id, inviter_oid, restaurant_name):
        try:

            class GoodsOrder(object):
                pass

            class User(object):
                pass

            class UserAddress(object):
                pass

            session = self.get_db_session(
                [
                    {"db_table": "ebt_user", "model": User},
                    {"db_table": "sdet_address", "model": UserAddress},
                    {"db_table": "sdet_order", "model": GoodsOrder},
                ]
            )
            filter = dict(sdef_address_device_id=open_id, sdef_address_is_del=0)
            address = (
                session.query(UserAddress)
                .filter_by(**filter)
                .order_by(UserAddress.sdef_address_create_time.desc())
                .first()
            )
            user = session.query(User).filter_by(ebf_user_id=open_id).first()
            if open_id == inviter_oid:
                if user and user.ebf_user_recommend_user:
                    inviter_oid = user.ebf_user_recommend_user

            ip = self.request.remote_ip
            now = datetime.datetime.now()
            order = GoodsOrder()
            out_trade_no = generator_trade_no()
            order.sdef_order_id = out_trade_no
            order.sdef_order_factory_uid = FACTORY_UID
            order.sdef_order_device_id = open_id
            order.sdef_order_fee = 0
            order.sdef_order_name = "餐厅免费加盟订单"
            order.sdef_order_type = OrderType.MEMBER
            order.sdef_order_pay_type = 2
            order.sdef_order_ip = ip
            order.sdef_order_delivery_fee = 0
            order.sdef_order_create_time = now
            order.sdef_order_pay_time = now
            order.sdef_order_message = "1"
            order.sdef_order_status = 2
            order.sdef_order_pay_status = 1
            order.sdef_order_describe = inviter_oid
            if address:
                address_id = address.sdef_address_id
                logger.info("address_id=%s" % address_id)
                order.sdef_order_address_id = address_id

            if user and user.ebf_user_agency_uid:
                agency_uid = user.ebf_user_agency_uid
            else:
                agency_uid = config.DEFAULT_AGENCY_UID

            order.sdef_order_agency_uid = agency_uid
            order.sdef_order_remarks = "餐厅免费加盟订单(推荐人为%s):%s" % (
                inviter_oid,
                restaurant_name,
            )
            session.add(order)
            session.commit()
            session.close()
            logger.info("创建免费加盟订单成功：oid=%s, inviter_oid=%s" % (open_id, inviter_oid))
        except Exception as e:
            logger.error("创建免费加盟订单失败： error=%s" % e)

    async def get(self):
        class UserAddressModel(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_address", "model": UserAddressModel},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user_agency", "model": UserAgency},
            ]
        )

        open_id = await self.get_open_id()
        default_address = AddressHelper.get_default(open_id)
        if default_address:
            address = (
                session.query(UserAddressModel)
                .filter_by(sdef_address_id=default_address["address_id"])
                .first()
            )
        else:
            # 尝试获取第一个地址
            address = (
                session.query(UserAddressModel)
                .filter_by(sdef_address_device_id=open_id, sdef_address_is_del=0)
                .order_by(UserAddressModel.sdef_address_id.desc())
                .first()
            )

        if not address:
            # ua = session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()
            # if ua:
            #     agency = session.query(Agency).filter_by(ebf_agency_id=ua.ebf_agency_id).first()
            #     address = dict(
            #         name=agency.ebf_agency_name,
            #         phone=agency.ebf_agency_contact
            #     )
            #     session.close()
            #     return self.finish(ret_msg(data=address))
            # else:
            #     return self.finish(ret_msg(data={}))
            return self.finish(ret_msg(data={}))

        address = dict(
            name=address.sdef_address_name,
            phone=address.sdef_address_phone,
            province=address.sdef_address_province,
            city=address.sdef_address_city,
            county=address.sdef_address_county,
            detail=address.sdef_address_detail,
            address_id=address.sdef_address_id,
        )
        session.close()
        return self.finish(ret_msg(data=address))

    async def post(self):
        open_id = await self.get_open_id()
        name = self.json_args.get("name", "").strip()
        phone = self.json_args.get("phone", "").strip()
        main_address = self.json_args.get("main_address", "").strip()
        address = self.json_args.get("address", "").strip()
        address_id = int(self.json_args.get("address_id", 0))

        # 餐厅免费加盟注册身份(3个#之间的代码为注册身份特有)
        ###
        type = self.json_args.get("type", None)
        inviter_oid = self.json_args.get("oid", None)
        restaurant_name = self.json_args.get("restaurant_name", None)
        if type == "freeshop":
            logger.info("inviter_oid=%s, open_id=%s" % (inviter_oid, open_id))
            if not inviter_oid:
                return self.write(ret_msg(code=-1, error_message="邀请人唯一标识为空！"))

            result = await self.register(open_id, inviter_oid)
            if not result:
                logger.error(
                    "免费加盟失败： inviter_oid=%s, open_id=%s" % (inviter_oid, open_id)
                )
                return self.write(ret_msg(code=-1, error_message="系统繁忙，请稍后重试！"))

            logger.info("免费加盟成功： inviter_oid=%s, open_id=%s" % (inviter_oid, open_id))
        ###
        # 线上分享213/499创建酒庄代表身份(# **之间代码)
        # **
        elif type == "shareonline":
            logger.info("inviter_oid=%s, open_id=%s" % (inviter_oid, open_id))
            if not inviter_oid:
                return self.write(ret_msg(code=-1, error_message="邀请人唯一标识为空！"))

            result = await self.register(open_id, inviter_oid)
            if not result:
                logger.error(
                    "创建普通用户账号失败： inviter_oid=%s, open_id=%s" % (inviter_oid, open_id)
                )
                return self.write(ret_msg(code=-1, error_message="系统繁忙，请稍后重试！"))

            result = self.create_agency(open_id, inviter_oid, name, phone)
            if result == -1:
                return self.write(ret_msg(code=-1, error_message="创建酒庄代表身份失败！"))
            elif result == 1:
                return self.write(ret_msg(code=-1, error_message="邀请人不存在！"))
        # **

        if not all((name, phone, main_address, address)):
            return self.write(ret_msg(code=-1, error_message="缺少参数"))

        if not re.match(r"^1\d{10}$", phone):
            return self.write(ret_msg(-1, error_message="请输入正确的手机号"))

        main_address_list = main_address.split(" ")
        if len(main_address_list) != 3:
            return self.write(ret_msg(-1, error_message="省市区格式不正确"))

        class UserAddressModel(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_address", "model": UserAddressModel},
            ]
        )
        now = datetime.datetime.now()
        province = main_address_list[0].strip()
        city = main_address_list[1].strip()
        county = main_address_list[2].strip()
        if address_id:
            old_address = (
                session.query(UserAddressModel)
                .filter_by(sdef_address_id=address_id)
                .first()
            )
            if not old_address:
                return self.write(ret_msg(-1, error_message="地址编号错误!"))
            is_name = False
            is_phone = False
            is_province = False
            is_city = False
            is_county = False
            is_address = False
            if name == old_address.sdef_address_name.strip():
                is_name = True
            if phone == old_address.sdef_address_phone.strip():
                is_phone = True
            if province == old_address.sdef_address_province:
                is_province = True
            if city == old_address.sdef_address_city:
                is_city = True
            if county == old_address.sdef_address_county:
                is_county = True
            if address == old_address.sdef_address_detail.strip():
                is_address = True
            if (
                is_name
                and is_phone
                and is_province
                and is_city
                and is_county
                and is_address
            ):
                old_address.sdef_address_create_time = now
                session.commit()
                session.close()
                logger.info("没有改变地址：address_id=%s" % address_id)
                ###
                if type == "freeshop":
                    self.create_order(open_id, inviter_oid, restaurant_name)
                ###
                return self.finish(ret_msg())

        try:
            _address = UserAddressModel()
            _address.sdef_address_phone = phone
            _address.sdef_address_name = name
            _address.sdef_address_detail = address
            _address.sdef_address_device_id = open_id
            _address.sdef_address_is_del = 0
            _address.sdef_address_province = province
            _address.sdef_address_city = city
            _address.sdef_address_county = county
            _address.sdef_address_create_time = now
            session.add(_address)
            session.flush()
        except Exception as e:
            session.rollback()
            session.close()
            logging.error(e)
            return self.write(ret_msg(code=-1, error_message="保存数据失败"))

        if not address_id:
            AddressHelper.add(
                open_id,
                _address.sdef_address_name,
                _address.sdef_address_phone,
                _address.sdef_address_province,
                _address.sdef_address_city,
                _address.sdef_address_county,
                _address.sdef_address_detail,
                _address.sdef_address_id,
                is_default=True,
            )
        else:
            AddressHelper.add(
                open_id,
                _address.sdef_address_name,
                _address.sdef_address_phone,
                _address.sdef_address_province,
                _address.sdef_address_city,
                _address.sdef_address_county,
                _address.sdef_address_detail,
                _address.sdef_address_id,
                is_default=False,
            )

        session.commit()
        session.close()
        ###
        if type == "freeshop":
            self.create_order(open_id, inviter_oid, restaurant_name)
        ###
        return self.finish(ret_msg())


# 新合伙人第一次进入合伙人后台前看完引导页后修改登陆状态
class FirstLoad(ApiBaseHandler):
    async def get(self):
        open_id = await self.get_open_id()
        try:
            db = mongodb_util.db
            result = db.users_login.find_one({"_id": open_id})
            if not result:
                return self.finish(ret_msg(data="OK"))
            db.users_login.update({"_id": open_id}, {"$set": {"login_times": 1}})
            logging.info("success")
        except Exception as e:
            logging.error("fail:error=%s" % e)
            return self.finish(ret_msg(code=-1, error_message="修改数据失败"))
        return self.finish(ret_msg(data="OK"))


class Cart(ApiBaseHandler):
    def data_received(self, chunk):
        pass

    async def get(self):
        open_id = await self.get_open_id()
        is_pad = True if re.match(r"^\d+$", open_id) else False
        is_vip = self.is_vip(open_id)
        is_membership = self.is_membership(open_id)
        logger.debug("是否为会员，open_id=%s,is_membership=%s" % (open_id, is_membership))

        class Goods(object):
            pass

        class Carts(object):
            pass

        class UserAddress(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "sdet_cart", "model": Carts},
                {"db_table": "sdet_address", "model": UserAddress},
            ]
        )
        cart_array = session.query(Carts).filter_by(sdef_cart_device_id=open_id).all()
        cart_goods_array = []
        cart_goods = []
        price_total = Decimal(0)
        if len(cart_array) > 0:
            cart_goods = json.loads(cart_array[0].sdef_cart_goods)
            # 清空购物车中已下架或没有库存的商品
            id_list = list()
            for c in cart_goods:
                id = c["id"]
                g = (
                    session.query(Goods)
                    .filter(Goods.sdef_goods_count > 0)
                    .filter_by(sdef_goods_status=1, sdef_goods_is_delete=0)
                    .filter_by(sdef_goods_id=id)
                    .first()
                )
                if not g:
                    id_list.append(id)

            if id_list:
                logger.info("id_list=%s" % id_list)
                cart_goods = list(filter(lambda x: x["id"] not in id_list, cart_goods))
                if cart_goods:
                    session.query(Carts).filter_by(sdef_cart_device_id=open_id).update(
                        {Carts.sdef_cart_goods: json.dumps(cart_goods)}
                    )
                else:
                    ret = (
                        session.query(Carts)
                        .filter_by(sdef_cart_device_id=open_id)
                        .delete()
                    )
                    logger.info("删除购物车: delete cart ret=%s" % ret)
                session.commit()

        for c in cart_goods:
            goods_id = c["id"]
            count = c["count"]
            _goods = session.query(Goods).filter_by(sdef_goods_id=goods_id).first()
            # goods_price = _goods.sdef_goods_member_price if is_membership else _goods.sdef_goods_price
            goods_price = (
                _goods.sdef_goods_member_price if is_vip else _goods.sdef_goods_price
            )
            goods = dict(
                id=goods_id,
                count=count,
                goods_img=json.loads(_goods.sdef_goods_thumbnail)[0],
                goods_name=_goods.sdef_goods_name,
                goods_price=str(goods_price.quantize(Decimal("0.00"))),
                is_buy=c.get("is_buy", 0),
                mpq=_goods.sdef_goods_mpq,
            )
            price_total += goods_price * Decimal(count)
            cart_goods_array.append(goods)

        default_address = AddressHelper.get_default(open_id)
        use_address = AddressHelper.get_use(open_id)
        db = mongodb_util.db
        address = None
        if use_address:
            logger.debug("使用地址，address_id=%s" % use_address["address_id"])
            address = (
                session.query(UserAddress)
                .filter_by(sdef_address_id=use_address["address_id"])
                .first()
            )
        elif default_address:
            logger.debug("默认地址，address_id=%s" % default_address["address_id"])
            address = (
                session.query(UserAddress)
                .filter_by(sdef_address_id=default_address["address_id"])
                .first()
            )
        else:
            result = db.sdec_address.find(
                {"user_id": open_id, "is_delete": False}
            ).sort("update_time", pymongo.DESCENDING)
            for a in result:
                address = (
                    session.query(UserAddress)
                    .filter_by(sdef_address_id=a["address_id"])
                    .first()
                )
                break
        if address:
            address_dict = dict(
                province=address.sdef_address_province,
                city=address.sdef_address_city,
                county=address.sdef_address_county,
                detail=address.sdef_address_detail,
                name=address.sdef_address_name,
                phone=address.sdef_address_phone,
            )

        context = dict(
            text="购物车",
            cart_goods_array=cart_goods_array,
            price_total=str(price_total.quantize(Decimal("0.00"))),
            address=address_dict if address else None,
            open_id=open_id,
            device_id=open_id,
            is_pad=is_pad,
        )
        session.close()
        return self.finish(ret_msg(data=context))

    async def post(self):
        open_id = await self.get_open_id()

        action = self.get_parameter("action")

        class Carts(object):
            pass

        class Goods(object):
            pass

        if action == "mod-cart-count":
            goods_id = self.get_parameter("goods_id")
            count = int(self.get_parameter("count"))
            if count <= 0:
                return self.write(ret_msg(-1, error_message="商品数量必须大于等于0"))

            session = self.get_db_session(
                [
                    {"db_table": "sdet_cart", "model": Carts},
                    {"db_table": "sdet_goods", "model": Goods},
                ]
            )

            # 检查库存：必须是上架+未删除+库存大于0
            goods = (
                session.query(Goods)
                .filter(Goods.sdef_goods_count > 0)
                .filter_by(
                    sdef_goods_id=goods_id, sdef_goods_status=1, sdef_goods_is_delete=0
                )
                .first()
            )
            if not goods:
                session.close()
                return self.write(ret_msg(-1, error_message="商品库存不足或已下架"))

            # 检查数量是否超出库存
            if count > goods.sdef_goods_count:
                session.close()
                return self.write(ret_msg(-1, error_message="商品库存不足"))

            cart_array = (
                session.query(Carts).filter_by(sdef_cart_device_id=open_id).all()
            )
            if len(cart_array) > 0:
                cart_goods = json.loads(cart_array[0].sdef_cart_goods)
            else:
                cart_goods = []

            for c in cart_goods:
                if c.get("id") == goods_id:
                    c["count"] = int(count)
                    c["is_buy"] = 1
                    session.query(Carts).filter_by(sdef_cart_device_id=open_id).update(
                        {Carts.sdef_cart_goods: json.dumps(cart_goods)}
                    )
                    # 提交
                    session.commit()
                    # 计算购物车商品数量
                    cart_count = 0
                    for c1 in cart_goods:
                        cart_count += c1["count"]
                    session.close()
                    return self.write(ret_msg(data=cart_count))
            session.close()
            return self.write(ret_msg(-1, error_message="购物车不存在此商品"))
        if action == "del-cart-goods":
            goods_id = self.get_parameter("goods_id")

            session = self.get_db_session(
                [
                    {"db_table": "sdet_cart", "model": Carts},
                ]
            )

            cart_array = (
                session.query(Carts).filter_by(sdef_cart_device_id=open_id).all()
            )
            if len(cart_array) > 0:
                cart_goods = json.loads(cart_array[0].sdef_cart_goods)
            else:
                cart_goods = []

            cart_goods_new = []
            for c in cart_goods:
                if c.get("id") == goods_id:
                    continue
                cart_goods_new.append(c)
            session.query(Carts).filter_by(sdef_cart_device_id=open_id).update(
                {Carts.sdef_cart_goods: json.dumps(cart_goods_new)}
            )
            # session.flush()
            session.commit()
            session.close()
            return self.write(ret_msg())
        return self.write(ret_msg())


class Order(ApiBaseHandler):
    async def get(self):
        open_id = await self.get_open_id()
        order_status = int(self.get_parameter("t", 0))
        order_type = int(self.get_parameter("order_type", 0))

        # 通用参数
        page_index = int(self.get_parameter("page_index", 0))
        page_size = int(self.get_parameter("page_size", 10))
        # 检查参数的合法性
        ApiHelper.inspect_common_params(page_index, page_size)
        page_start = page_index * page_size

        class GoodsOrder(object):
            pass

        class Goods(object):
            pass

        class User(object):
            pass

        class Agency(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_order", "model": GoodsOrder},
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_agency", "model": Agency},
            ]
        )
        filters = dict(sdef_order_is_delete=0, sdef_order_device_id=open_id)

        if order_status:
            filters["sdef_order_status"] = order_status

        # 订单类型（1=普通订单，2=送礼订单，3=加盟费订单，4=特惠订单，5=餐券抵扣订单，6=礼品卡订单，7=新礼品订单，8=体验卡买单订单）
        if order_type:
            if order_type == 67:  # 6=送礼订单 7=收礼订单
                _order_array = (
                    session.query(GoodsOrder)
                    .filter_by(**filters)
                    .filter(
                        or_(
                            GoodsOrder.sdef_order_type == 6,
                            GoodsOrder.sdef_order_type == 7,
                        )
                    )
                    .order_by(GoodsOrder.sdef_order_id.desc())[
                        page_start : page_start + page_size
                    ]
                )
            else:
                _order_array = (
                    session.query(GoodsOrder)
                    .filter_by(**filters)
                    .filter_by(sdef_order_type=order_type)
                    .order_by(GoodsOrder.sdef_order_id.desc())[
                        page_start : page_start + page_size
                    ]
                )
        else:
            _order_array = (
                session.query(GoodsOrder)
                .filter_by(**filters)
                .filter(GoodsOrder.sdef_order_type != 3)
                .order_by(GoodsOrder.sdef_order_id.desc())[
                    page_start : page_start + page_size
                ]
            )

        order_array = []
        for o in _order_array:
            data = None
            if o.sdef_order_status == OrderStatus.WAIT_PAY:
                _status = "待支付"
            elif (
                o.sdef_order_status == OrderStatus.WAIT_EXPRESS
                or o.sdef_order_status == OrderStatus.WAIT_PICKUP
            ):
                _status = "待发货"
            elif o.sdef_order_status == OrderStatus.EXPRESSED:
                _status = "已发货"
                try:
                    if o.sdef_order_express_no:
                        order_id = o.sdef_order_id
                        express_no = json.loads(o.sdef_order_express_no)
                        if len(express_no) <= 0:
                            raise Exception("没有物流信息:order_id=%s" % order_id)

                        express_no_item = express_no[0]
                        if not isinstance(express_no_item, dict):
                            logger.debug(express_no_item)
                            raise Exception("物流信息格式不对:order_id=%s" % order_id)

                        express_symbol = express_no_item.get("express_symbol")
                        express_number = express_no_item.get("express_number")
                        # 使用tornado的异步查询
                        http = httpclient.AsyncHTTPClient()

                        url = "https://poll.kuaidi100.com/poll/query.do"
                        param = (
                            '{"com":"'
                            + express_symbol.lower()
                            + '","num":"'
                            + express_number
                            + '"}'
                        )
                        s = ExpressHelper.sign(param)
                        data = dict(
                            customer=KUAIDI100_CUSTOMER,
                            sign=s,
                            param=param,
                        )
                        logger.debug("params=%s" % data)
                        url = url_concat(url, data)
                        request = HTTPRequest(
                            url,
                            body=json_encode(data),
                            method="POST",
                            validate_cert=False,
                        )
                        logger.debug("异步请求开始")
                        result = await http.fetch(request)
                        r = result.body.decode()
                        obj = json.loads(r)
                        if obj.get("message") != "ok":
                            pass
                        else:
                            data = obj.get("data")
                        logger.debug("异步请求挂起，执行其它任务")
                except Exception as e:
                    logger.exception(e)
            elif o.sdef_order_status == OrderStatus.CHECK:
                _status = "审核中"
            elif o.sdef_order_status == OrderStatus.RECEIVED:
                _status = "已收货"
            elif o.sdef_order_status == OrderStatus.AFTER_SALE:
                _status = "售后中"
            elif o.sdef_order_status == OrderStatus.COMPLETE:
                _status = "完成"
            elif o.sdef_order_status == OrderStatus.INVALID:
                _status = "失效"
            elif o.sdef_order_status == OrderStatus.REFUND:
                _status = "已退款"
            elif o.sdef_order_status == OrderStatus.WAIT_VALID:
                _status = "待生效"
            else:
                _status = "未知"

            if o.sdef_order_pay_status == PayStatus.REFUND:
                _status = "已退款"

            price_total = Decimal(0)
            store_id = o.sdef_order_store_id
            flag = 1  # 1=表示门店还在， 0=表示门店已撤销
            if store_id > 0:
                agency = session.query(Agency).filter_by(ebf_agency_id=store_id).first()
                if not agency:
                    logger.error(
                        "门店不存在： order_id=%s, store_id=%s" % (o.sdef_order_id, store_id)
                    )
                    continue

                if agency.ebf_agency_type != 3:
                    flag = 0
                store_info = dict(
                    store_id=store_id,
                    store_name=agency.ebf_agency_name,
                    flag=flag,
                    lng=float(
                        agency.ebf_agency_longitude
                        if agency.ebf_agency_longitude
                        else 0
                    ),
                    lat=float(
                        agency.ebf_agency_latitude if agency.ebf_agency_latitude else 0
                    ),
                    address=agency.ebf_agency_address,
                )
            else:
                store_info = {}
            cart_goods = json.loads(o.sdef_order_goods)
            for c in cart_goods:
                price_total += Decimal(c["goods_price"]) * Decimal(c["count"])

            if o.sdef_order_type == OrderType.PINGUI:
                service_fee = ApiHelper.service_fee(price_total)
            else:
                service_fee = Decimal(0)
            delivery_fee = o.sdef_order_delivery_fee
            delivery_fee = Decimal(delivery_fee) if delivery_fee else Decimal(0)
            price_total += service_fee
            price_total += delivery_fee
            # 体验待生效订单已推荐订单数目
            if o.sdef_order_status == OrderStatus.WAIT_VALID:
                user = session.query(User).filter_by(ebf_user_id=open_id).first()
                order_number = user.ebf_user_recommend_order_number
            else:
                order_number = 0

            order_array.append(
                dict(
                    order_id=o.sdef_order_id,
                    status=_status,
                    cart_goods=cart_goods,
                    goods_count=len(cart_goods),
                    price_total="%.2f" % price_total,
                    service_fee="%.2f" % service_fee,
                    delivery_fee="%.2f" % delivery_fee,
                    order_fee="%.2f" % o.sdef_order_fee,
                    per_order_type=o.sdef_order_type,
                    express_info=data,
                    create_time=o.sdef_order_create_time.strftime("%Y-%m-%d %H:%M:%S"),
                    pay_type=o.sdef_order_pay_type,
                    order_status=o.sdef_order_status,
                    store_info=store_info,
                    order_number=order_number,
                    store_id=store_id,
                )
            )

        context = dict(
            text="订单查询",
            order_array=order_array,
            order_status=order_status,
            open_id=open_id,
            device_id=open_id,
        )
        session.close()
        return self.finish(ret_msg(data=context))

    async def post(self):
        open_id = await self.get_open_id()
        device_id = self.json_args.get("device_id", "")
        action = self.json_args.get("action", "")
        order_id = self.json_args.get("order_id", "")

        if not all((action, order_id)):
            return self.finish(ret_msg(code=-1, error_message="缺少参数"))

        class GoodsOrder(object):
            pass

        class Goods(object):
            pass

        class CouponOrder(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_order", "model": GoodsOrder},
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "ebt_coupon_order", "model": CouponOrder},
            ]
        )

        _filter = dict(
            sdef_order_id=order_id,
        )
        if device_id:
            _filter["sdef_order_describe"] = device_id
        else:
            _filter["sdef_order_device_id"] = open_id
        _order = session.query(GoodsOrder).filter_by(**_filter).all()[0]
        if action == "cancel":
            if _order.sdef_order_status not in [
                OrderStatus.WAIT_PAY,
                OrderStatus.WAIT_EXPRESS,
                OrderStatus.WAIT_PICKUP,
            ]:
                ret = ret_msg(-1, error_message="只有待支付、待发货的订单才能取消")
                session.close()
                return self.finish(ret)

            if _order.sdef_order_type == OrderType.NEW_GIFT:
                session.close()
                return self.finish(ret_msg(code=-1, error_message="礼品订单不能取消"))

            if _order.sdef_order_status == OrderStatus.WAIT_PAY:
                _order.sdef_order_status = OrderStatus.INVALID
                _order.sdef_order_is_delete = 1
                _order.sdef_order_delete_time = datetime.datetime.now()
                order_goods = json.loads(_order.sdef_order_goods)
                order_type = _order.sdef_order_type
                store_id = _order.sdef_order_store_id
                goods_packing_id = ["571983673114813", "571983568187916"]  # 商品包装ID列表
                for g in order_goods:
                    goods = (
                        session.query(Goods).filter_by(sdef_goods_id=g["id"]).first()
                    )
                    if goods:
                        if (
                            order_type == OrderType.PINQU
                            and not store_id
                            and g["id"] not in goods_packing_id
                        ):
                            continue
                        goods.sdef_goods_count += int(g["count"])

                if _order.sdef_order_coupon_fee > Decimal("0"):
                    filters = dict(
                        user_id=open_id,
                        order_id=order_id,
                        money=Decimal("139"),
                        status=0,
                    )
                    ret = session.query(CouponOrder).filter_by(**filters).delete()
                    logger.info(
                        "delete coupon_order ret=%s, order_id=%s" % (ret, order_id)
                    )
                session.commit()

                # 取消订单时解锁余额
                if _order.sdef_order_balance_fee > Decimal("0"):
                    redis = redis_util.client
                    lock_balance_fee = redis.get("balance_lock_%s" % open_id)
                    if lock_balance_fee:
                        lock_balance_fee = Decimal(lock_balance_fee.decode())
                        lock_balance_fee -= _order.sdef_order_balance_fee
                        if lock_balance_fee > Decimal("0"):
                            redis.setex(
                                "balance_lock_%s" % open_id, 600, str(lock_balance_fee)
                            )
                        else:
                            redis.delete("balance_lock_%s" % open_id)
            elif (
                _order.sdef_order_status == OrderStatus.WAIT_EXPRESS
                or _order.sdef_order_status == OrderStatus.WAIT_PICKUP
            ):
                # 已支付的订单取消
                goods_id1 = "561774248859721"  # 私人酒庄商品
                goods_id2 = "562225951936393"  # 经销商加盟商品
                goods_id3 = promotion.NEW_CUSTOMER_PROMO_GOODS_ID  # 新人礼商品
                order_goods = _order.sdef_order_goods  # 商品信息字符串
                if (
                    goods_id1 in order_goods
                    or goods_id2 in order_goods
                    or goods_id3 in order_goods
                ):
                    session.close()
                    return self.write(ret_msg(code=-1, error_message="该订单不能取消"))

                if _order.sdef_order_type in [OrderType.PINQU, OrderType.TIYAN]:
                    session.close()
                    return self.write(ret_msg(code=-1, error_message="该订单不能取消"))

                _order.sdef_order_status = OrderStatus.CHECK
                session.commit()
                logger.info(
                    "订单状态修改成功：order_id=%s,是否审核退款=%s"
                    % (order_id, CANCEL_PAID_ORDER_IS_NEED_CHECK)
                )
                if not CANCEL_PAID_ORDER_IS_NEED_CHECK:
                    cancel_order_immediate_refund(order_id)
                else:
                    tasks.order_refund_applied.delay(order_id)
            session.close()
            return self.finish(ret_msg())


class OrderDetail(ApiBaseHandler):
    async def get(self, order_id):
        open_id = await self.get_open_id()
        user = UserHelper.get_user(open_id)
        agency_uid = user.ebf_user_agency_uid
        agency_id, store_id = self.store_agency_id(open_id)
        supplier_id = UserHelper.get_supplier_id(agency_uid)
        is_supplier = UserHelper.is_supplier_staff(agency_uid)
        device_id = self.get_parameter("device_id", None)

        class GoodsOrder(object):
            pass

        class Goods(object):
            pass

        class UserAddress(object):
            pass

        class User(object):
            pass

        class Agency(object):
            pass

        class GiftInfo(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_order", "model": GoodsOrder},
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "sdet_address", "model": UserAddress},
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_gift_info", "model": GiftInfo},
            ]
        )

        filters = dict(
            sdef_order_id=order_id,
        )

        orders = (
            session.query(GoodsOrder)
            .filter_by(**filters)
            .order_by(GoodsOrder.sdef_order_id.desc())
            .all()
        )
        if len(orders) > 0:
            o = orders[0]
        else:
            return self.write(ret_msg(code=-1, error_message="订单不存在!"))

        # 授权查看订单
        if (
            o.sdef_order_device_id != open_id  # 允许自己查看
            and o.sdef_order_describe != device_id  # 允许设备查看
            and not (store_id and o.sdef_order_store_id == store_id)  # 允许门店查看
            and not (is_supplier and o.sdef_order_supplier_id == supplier_id)  # 允许供应商查看
            and o.sdef_order_agency_uid != agency_uid  # 允许所属合伙人查看
        ):
            return self.write(ret_msg(code=-1, error_message="您无权限查看这个订单!"))

        if o.sdef_order_status == OrderStatus.WAIT_PAY:
            _status = "待支付"
        elif o.sdef_order_status == OrderStatus.WAIT_EXPRESS:
            _status = "待发货"
        elif o.sdef_order_status == OrderStatus.WAIT_PICKUP:
            _status = "待提货"
        elif o.sdef_order_status == OrderStatus.EXPRESSED:
            _status = "已发货"
        elif o.sdef_order_status == OrderStatus.CHECK:
            _status = "审核中"
        elif o.sdef_order_status == OrderStatus.RECEIVED:
            _status = "已收货"
        elif o.sdef_order_status == OrderStatus.AFTER_SALE:
            _status = "售后中"
        elif o.sdef_order_status == OrderStatus.COMPLETE:
            _status = "完成"
        elif o.sdef_order_status == OrderStatus.INVALID:
            _status = "失效"
        elif o.sdef_order_status == OrderStatus.REFUND:
            _status = "已退款"
        elif o.sdef_order_status == OrderStatus.WAIT_VALID:
            _status = "待生效"
        else:
            _status = "未知"

        if o.sdef_order_pay_status == PayStatus.REFUND:
            _status = "已退款"

        if o.sdef_order_pay_status == 1:
            pay_status = "已支付"
        elif o.sdef_order_pay_status == 2:
            pay_status = "已退款"
        elif o.sdef_order_pay_status == 0:
            pay_status = "未支付"
        else:
            pay_status = "未知"

        cart_goods = json.loads(o.sdef_order_goods)
        order_express_no = []
        try:
            if o.sdef_order_express_no:
                order_express_no = json.loads(o.sdef_order_express_no)
                if len(order_express_no) > 0:
                    express_no_item = order_express_no[0]
                    if isinstance(express_no_item, dict):
                        order_express_no = [
                            express_no_item.get("express_number")
                            + " 【%s】" % express_no_item.get("express_name")
                        ]
        except Exception as e:
            logger.exception(e)

        encrypt_order_id = GiftHelper.encrypt_order_id(o.sdef_order_id)
        address = (
            session.query(UserAddress)
            .filter_by(sdef_address_id=o.sdef_order_address_id)
            .first()
        )
        address_dict = (
            dict(
                name=address.sdef_address_name,
                phone=address.sdef_address_phone,
                province=address.sdef_address_province,
                city=address.sdef_address_city,
                county=address.sdef_address_county,
                detail=address.sdef_address_detail,
            )
            if address
            else {}
        )

        host = self.request.host
        protocol = self.request.protocol
        gift_full_url = protocol + "://" + host + "/gift/" + encrypt_order_id
        is_wechat = self.is_in_wechat()
        store_id = o.sdef_order_store_id
        flag = 1  # 1=表示门店还在， 0=表示门店已撤销
        if store_id > 0:
            agency = session.query(Agency).filter_by(ebf_agency_id=store_id).first()
            if not agency:
                logger.error(
                    "门店不存在： order_id=%s, store_id=%s" % (o.sdef_order_id, store_id)
                )
                store_info = {}
            else:
                if agency.ebf_agency_type != 3:
                    flag = 0
                store_info = dict(
                    store_id=store_id,
                    store_name=agency.ebf_agency_name,
                    flag=flag,
                    lng=float(
                        agency.ebf_agency_longitude
                        if agency.ebf_agency_longitude
                        else 0
                    ),
                    lat=float(
                        agency.ebf_agency_latitude if agency.ebf_agency_latitude else 0
                    ),
                    address=agency.ebf_agency_address,
                    phone=agency.ebf_agency_contact,
                )
        else:
            store_info = {}

        goods_total_fee = 0
        for c in cart_goods:
            goods_total_fee += Decimal(c["goods_price"]) * Decimal(c["count"])

        if o.sdef_order_type == OrderType.PINGUI:
            service_fee = ApiHelper.service_fee(goods_total_fee)
        else:
            service_fee = Decimal(0)
        delivery_fee = o.sdef_order_delivery_fee
        delivery_fee = Decimal(delivery_fee) if delivery_fee else Decimal(0)

        # 体验待生效订单已推荐订单数目
        if o.sdef_order_status == OrderStatus.WAIT_VALID:
            user = session.query(User).filter_by(ebf_user_id=open_id).first()
            order_number = user.ebf_user_recommend_order_number
        else:
            order_number = 0

        # 送礼订单信息
        gift_receiver = ""
        gift_receiver_order = ""
        gift_receive_time = ""
        if (
            o.sdef_order_type == OrderType.GIFT_CARD
            and o.sdef_order_status == OrderStatus.COMPLETE
        ):
            gift = (
                session.query(GiftInfo).filter_by(gift_sender_order_id=order_id).first()
            )
            gift_receiver = UserHelper.get_user(gift.receiver).ebf_user_nickname
            gift_receiver_order = gift.gift_receiver_order_id
            gift_receive_time = gift.update_time.strftime(
                "%Y{y}%m{m}%d{d} %H:%M:%S"
            ).format(y="年", m="月", d="日")

        context = dict(
            is_wechat=is_wechat,
            status=_status,
            pay_status=pay_status,
            is_pay=o.sdef_order_pay_status,
            order_id=o.sdef_order_id,
            order_express_no=order_express_no,
            delivery_fee="%.2f" % delivery_fee,
            goods_total_fee="%.2f" % goods_total_fee,
            service_fee="%.2f" % service_fee,
            cart_goods=cart_goods,
            create_time=o.sdef_order_create_time.strftime(
                "%Y{y}%m{m}%d{d} %H:%M:%S"
            ).format(y="年", m="月", d="日"),
            pay_time=o.sdef_order_pay_time.strftime("%Y/%m/%d %H:%M:%S")
            if o.sdef_order_pay_time
            else None,
            order_fee=str(o.sdef_order_fee.quantize(Decimal("0.00"))),
            balance_fee=str(o.sdef_order_balance_fee.quantize(Decimal("0.00"))),
            coupon_fee=str(o.sdef_order_coupon_fee.quantize(Decimal("0.00"))),
            goods_count=len(cart_goods),
            address=address_dict,
            per_order_type=o.sdef_order_type,
            message=o.sdef_order_message,
            pay_type=o.sdef_order_pay_type,
            order_status=o.sdef_order_status,
            store_info=store_info,
            order_number=order_number,
            store_id=store_id,
            gift_full_url=gift_full_url,
            gift_receiver=gift_receiver,
            gift_receiver_order=gift_receiver_order,
            gift_receive_time=gift_receive_time,
        )

        session.close()
        return self.finish(ret_msg(data=context))

    async def post(self, order_id):
        open_id = await self.get_open_id()
        user = UserHelper.get_user(open_id)
        agency_uid = user.ebf_user_agency_uid
        agency_id, store_id = self.store_agency_id(open_id)
        supplier_id = UserHelper.get_supplier_id(agency_uid)
        is_supplier = UserHelper.is_supplier_staff(agency_uid)
        device_id = self.get_parameter("device_id", None)
        action = self.get_parameter("action", None)

        class GoodsOrder(object):
            pass

        class Goods(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_order", "model": GoodsOrder},
                {"db_table": "sdet_goods", "model": Goods},
            ]
        )

        filters = dict(
            sdef_order_id=order_id,
        )

        orders = session.query(GoodsOrder).filter_by(**filters).all()
        if len(orders) > 0:
            o = orders[0]
        else:
            session.close()
            return self.write(ret_msg(code=-1, error_message="订单不存在！"))

        # 允许供应商/门店处理订单
        if (
            o.sdef_order_device_id != open_id
            and o.sdef_order_describe != device_id
            and not (store_id and o.sdef_order_store_id == store_id)
            and not (is_supplier and o.sdef_order_supplier_id == supplier_id)
        ):
            return self.write(ret_msg(code=-1, error_message="您无权限处理这个订单！"))

        if action == "confirm":
            if o.sdef_order_status != 3:
                ret = ret_msg(-1, error_message="只有已发货的订单才能确认收货")
                return self.finish(ret)

            if o.sdef_order_type == OrderType.GIFT and not o.sdef_order_address_id:
                ret = ret_msg(-1, error_message="此礼品订单未填写收货地址")
                return self.finish(ret)

            if o.sdef_order_type == OrderType.BARGAIN_PRICE:
                # 特惠订单不支持退换货
                o.sdef_order_status = OrderStatus.COMPLETE
                session.commit()
            else:
                if not add_mq_task(
                    order_id,
                    message_type=3,
                    delay=DAYS_AFTER_RECEIVED_FOR_AUTO_COMPLETION * 24 * 3600,
                ):
                    session.close()
                    return self.finish(ret_msg(-1, error_message="确认收货失败"))
                o.sdef_order_status = OrderStatus.RECEIVED
                session.commit()
            session.close()
            return self.finish(ret_msg())

        elif action == "get-express":
            try:
                if o.sdef_order_express_no:
                    express_no = json.loads(o.sdef_order_express_no)
                    if len(express_no) <= 0:
                        session.close()
                        raise Exception("没有物流信息:order_id=%s" % order_id)

                    express_no_item = express_no[0]
                    if not isinstance(express_no_item, dict):
                        logger.debug(express_no_item)
                        session.close()
                        raise Exception("物流信息格式不对:order_id=%s" % order_id)

                    express_symbol = express_no_item.get("express_symbol")
                    express_number = express_no_item.get("express_number")
                    # 使用tornado的异步查询
                    http = httpclient.AsyncHTTPClient()

                    url = "https://poll.kuaidi100.com/poll/query.do"
                    param = (
                        '{"com":"'
                        + express_symbol.lower()
                        + '","num":"'
                        + express_number
                        + '"}'
                    )
                    s = ExpressHelper.sign(param)
                    data = dict(
                        customer=KUAIDI100_CUSTOMER, sign=s, param=param
                    )
                    logger.debug("params=%s" % data)
                    url = url_concat(url, data)
                    request = HTTPRequest(
                        url, body=json_encode(data), method="POST", validate_cert=False
                    )
                    logger.debug("异步请求开始")
                    result = await http.fetch(request)
                    r = result.body.decode()
                    obj = json.loads(r)
                    if obj.get("message") != "ok":
                        ret = ret_msg(-1)
                    else:
                        ret = ret_msg(data=obj.get("data"))
                    self.finish(ret)
                    session.close()
                    logger.debug("异步请求挂起，执行其它任务")

            except Exception as e:
                logger.exception(e)


class ImageInfo(ApiBaseHandler):
    async def get(self):
        nums = int(self.get_parameter("nums", 3))

        class Goods(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_goods", "model": Goods},
            ]
        )
        goods_list = (
            session.query(Goods)
            .filter_by(
                sdef_goods_status=1,
                sdef_goods_is_delete=0,
                sdef_goods_factory_uid=config.FACTORY_UID,
            )
            .order_by(Goods.sdef_goods_update_time.desc())
            .all()
        )
        imgs_info = []
        for g in goods_list:
            img = {}
            urls = json.loads(g.sdef_goods_thumbnail)
            if len(urls) > 2:
                img["img_url"] = urls[2]
                img["goods_url"] = "/mall/detail/" + g.sdef_goods_id
                imgs_info.append(img)
        imgs_info = imgs_info[0:nums]
        session.close()
        return self.finish(ret_msg(data=imgs_info))


class ModifyAddress(ApiBaseHandler):
    async def get(self):
        class UserAddress(object):
            pass

        class GoodsOrder(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_address", "model": UserAddress},
                {"db_table": "sdet_order", "model": GoodsOrder},
            ]
        )

        await self.get_open_id()
        order_id = self.get_parameter("order_id", "")
        if not order_id:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数订单编号"))

        order = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
        if not order:
            return self.write(ret_msg(code=-1, error_message="要修改的订单不存在"))

        order_status = order.sdef_order_status
        if order_status != 2:
            return self.write(ret_msg(code=-1, error_message="只有待发货的订单才可以修改"))

        price_total = Decimal(0)
        cart_goods = json.loads(order.sdef_order_goods)
        for c in cart_goods:
            price_total += Decimal(c["goods_price"]) * Decimal(c["count"])

        _status = "待发货"
        order_dict = dict(
            order_id=order.sdef_order_id,
            status=_status,
            cart_goods=cart_goods,
            goods_count=len(cart_goods),
            price_total=str(
                (order.sdef_order_fee + order.sdef_order_balance_fee).quantize(
                    Decimal("0.00")
                )
            ),
            per_order_type=order.sdef_order_type,
        )
        address = (
            session.query(UserAddress)
            .filter_by(sdef_address_id=order.sdef_order_address_id)
            .first()
        )
        address_dict = (
            dict(
                name=address.sdef_address_name,
                phone=address.sdef_address_phone,
                province=address.sdef_address_province,
                city=address.sdef_address_city,
                county=address.sdef_address_county,
                detail=address.sdef_address_detail,
            )
            if address
            else {}
        )
        order_dict["address"] = address_dict
        session.close()
        return self.write(ret_msg(data=order_dict))

    async def post(self):
        class UserAddress(object):
            pass

        class GoodsOrder(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_address", "model": UserAddress},
                {"db_table": "sdet_order", "model": GoodsOrder},
            ]
        )

        open_id = await self.get_open_id()
        order_id = self.json_args.get("order_id", "")
        name = self.json_args.get("name", "")
        phone = self.json_args.get("phone", "")
        main_address = self.json_args.get("main_address", "")  # 省市区
        address = self.json_args.get("address", "")  # 详细地址

        if not all((order_id, name, phone, main_address, address)):
            return self.write(ret_msg(code=-1, error_message="缺少参数"))

        if not re.match(r"^1\d{10}$", phone):
            return self.write(ret_msg(-1, error_message="请输入正确的手机号"))

        main_address_list = main_address.split(" ")
        if len(main_address_list) != 3:
            return self.write(ret_msg(-1, error_message="省市区格式不正确"))

        now = datetime.datetime.now()
        order = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()

        try:
            _address = UserAddress()
            _address.sdef_address_phone = phone
            _address.sdef_address_name = name
            _address.sdef_address_detail = address
            _address.sdef_address_device_id = open_id
            _address.sdef_address_is_del = 0
            _address.sdef_address_province = main_address_list[0].strip()
            _address.sdef_address_city = main_address_list[1].strip()
            _address.sdef_address_county = main_address_list[2].strip()
            _address.sdef_address_create_time = now
            session.add(_address)
            session.flush()
            order.sdef_order_address_id = _address.sdef_address_id
            session.commit()
        except Exception as e:
            session.rollback()
            session.close()
            logging.error(e)
            return self.write(ret_msg(code=-1, error_message="保存数据失败"))

        AddressHelper.add(
            open_id,
            _address.sdef_address_name,
            _address.sdef_address_phone,
            _address.sdef_address_province,
            _address.sdef_address_city,
            _address.sdef_address_county,
            _address.sdef_address_detail,
            _address.sdef_address_id,
            is_default=False,
        )
        session.close()
        return self.write(ret_msg())


class Address(ApiBaseHandler):
    def data_received(self, chunk):
        pass

    async def get(self):
        open_id = await self.get_open_id()
        is_pad = True if re.match(r"^\d+$", open_id) else False

        class UserAddress(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_address", "model": UserAddress},
            ]
        )

        address = None
        address_id = self.get_parameter("id", None)
        if address_id:
            filters = dict(
                sdef_address_id=address_id,
                sdef_address_is_del=0,
            )
            if is_pad:
                filters["sdef_address_device_id"] = open_id

            _address = (
                session.query(UserAddress)
                .filter_by(**filters)
                .order_by(UserAddress.sdef_address_id.desc())
                .first()
            )
            if _address:
                # 微信修改设备上的地址
                if re.match(r"^\d+$", _address.sdef_address_device_id):
                    address = _address
                elif _address.sdef_address_device_id == open_id:  # 避免其它人越权修改地址
                    address = _address
                if address:
                    address = dict(
                        id=address.sdef_address_id,
                        province=address.sdef_address_province,
                        city=address.sdef_address_city,
                        county=address.sdef_address_county,
                        detail=address.sdef_address_detail,
                        name=address.sdef_address_name,
                        phone=address.sdef_address_phone,
                    )

        context = dict(
            text="收货地址",
            address=address,
            open_id=open_id,
            device_id=open_id,
        )
        session.close()
        return self.write(ret_msg(data=context))

    async def post(self):
        open_id = await self.get_open_id()

        main_address = self.json_args.get("main_address", "")
        name = self.json_args.get("name", "")
        phone = self.json_args.get("phone", "")
        address = self.json_args.get("address", "")
        postal_code = self.json_args.get("postalCode", "")
        code = self.json_args.get("code", None)
        is_default = int(self.json_args.get("is_default", 0))
        is_use = int(self.json_args.get("is_use", 1))

        if not all((name, phone, main_address, address)):
            return self.write(ret_msg(code=-1, error_message="缺少参数"))

        if not re.match(r"^1\d{10}$", phone):
            return self.write(ret_msg(-1, error_message="请输入正确的手机号"))

        main_address_list = main_address.split(" ")
        if len(main_address_list) != 3:
            return self.write(ret_msg(-1, error_message="省市区格式不正确"))

        class UserAddress(object):
            pass

        class GoodsOrder(object):
            pass

        if code:
            decrypt_order_id = GiftHelper.decrypt_order_id(code)
            check_ret = GiftHelper.check_order(decrypt_order_id)
            if check_ret.get("code") != 0:
                return self.write(json.dumps(check_ret))

        session = self.get_db_session(
            [
                {"db_table": "sdet_order", "model": GoodsOrder},
                {"db_table": "sdet_address", "model": UserAddress},
            ]
        )
        _address = UserAddress()
        _address.sdef_address_phone = phone
        _address.sdef_address_name = name
        _address.sdef_address_postal_code = postal_code
        _address.sdef_address_detail = address
        # 支持礼物填写地址，填写完之后要更新订单中的地址
        if code:
            _address.sdef_address_device_id = decrypt_order_id
        else:
            _address.sdef_address_device_id = open_id

        address_id = self.json_args.get("id", None)
        logger.info("address_id=%s" % address_id)
        if address_id:
            filters = dict(
                sdef_address_id=int(address_id),
                sdef_address_is_del=0,
            )
            address_old = session.query(UserAddress).filter_by(**filters).first()

            if address_old and re.match(r"^\d+$", address_old.sdef_address_device_id):
                logger.info(
                    "修改设备上的地址：sdef_address_device_id=%s"
                    % address_old.sdef_address_device_id
                )
                _address.sdef_address_device_id = address_old.sdef_address_device_id

        _address.sdef_address_is_del = 0
        _address.sdef_address_province = main_address_list[0].strip()
        _address.sdef_address_city = main_address_list[1].strip()
        _address.sdef_address_county = main_address_list[2].strip()
        session.add(_address)
        session.flush()
        session.commit()

        if address_id:
            new_address_id = _address.sdef_address_id
            AddressHelper.update(
                open_id,
                _address.sdef_address_name,
                _address.sdef_address_phone,
                _address.sdef_address_province,
                _address.sdef_address_city,
                _address.sdef_address_county,
                _address.sdef_address_detail,
                address_id,
                is_default=None,
                new_address_id=new_address_id,
            )
        else:
            AddressHelper.add(
                open_id,
                _address.sdef_address_name,
                _address.sdef_address_phone,
                _address.sdef_address_province,
                _address.sdef_address_city,
                _address.sdef_address_county,
                _address.sdef_address_detail,
                _address.sdef_address_id,
                is_default=False,
            )

        if code:
            # 更新礼品订单地址
            update_fields = {GoodsOrder.sdef_order_address_id: _address.sdef_address_id}
            session.query(GoodsOrder).filter_by(sdef_order_id=decrypt_order_id).update(
                update_fields
            )
            session.commit()
            # session.close()

        is_default = True if is_default else False
        is_use = True if is_use else False
        if is_default:
            AddressHelper.set_default(
                open_id, _address.sdef_address_id, is_default, is_use
            )
        AddressHelper.set_default(open_id, _address.sdef_address_id, is_default, is_use)

        address = dict(
            id=_address.sdef_address_id,
            province=_address.sdef_address_province,
            city=_address.sdef_address_city,
            county=_address.sdef_address_county,
            detail=_address.sdef_address_detail,
            name=_address.sdef_address_name,
            phone=_address.sdef_address_phone,
        )

        session.close()
        return self.write(ret_msg(data=address))


class AddressManage(ApiBaseHandler):
    def data_received(self, chunk):
        pass

    async def get(self):
        open_id = await self.get_open_id()

        # class UserAddress(object):
        #     pass

        # session = self.get_session([
        #     {"db_table": "sdet_address", "model": UserAddress},
        # ])

        address_list = []
        # 从mongodb中获取地址列表
        db = mongodb_util.db
        address_count = db.sdec_address.find(
            {"user_id": open_id, "is_delete": False}
        ).count()
        logger.debug("address_count=%s" % address_count)
        if address_count > 0:
            all_address = db.sdec_address.find(
                {"user_id": open_id, "is_delete": False}
            ).sort("update_time", pymongo.DESCENDING)
            for a in all_address:
                address = dict(
                    province=a["province"],
                    city=a["city"],
                    county=a["county"],
                    detail_address=a["detail_address"],
                    name=a["name"],
                    phone=a["phone"],
                    is_default=a.get("is_default", False),
                    address_id=a["address_id"],
                )
                address_list.append(address)

        # session.close()
        context = dict(
            is_wechat=self.is_in_wechat(),
            open_id=open_id,
            title="收货地址列表",
            address_list=address_list,
        )
        return self.write(ret_msg(data=context))

    async def post(self):
        open_id = await self.get_open_id()

        action = self.json_args.get("action", None)
        address_id = self.json_args.get("address_id", None)

        if action == "delete":
            AddressHelper.delete_address(open_id, address_id)
            return self.write(ret_msg())
        elif action == "set-default":
            is_default = self.json_args.get("is_default", "true")
            is_default = True if is_default == "true" else False
            AddressHelper.set_default(open_id, address_id, is_default, is_use=True)
            return self.write(ret_msg())
        elif action == "set-use":
            address = AddressHelper.get_default(open_id)
            is_default = False
            if address:
                if address["address_id"] == address_id:
                    is_default = True
            AddressHelper.set_default(open_id, address_id, is_default, is_use=True)
            return self.write(ret_msg())
        return self.write(ret_msg(-1))


class BuyPartGoods(ApiBaseHandler):
    async def post(self):
        id_array = self.get_parameter("id_array", [])
        logger.info("id_array: %s, type(id_array): %s" % (id_array, type(id_array)))

        if not id_array or not isinstance(id_array, list):
            return self.write(ret_msg(code=-1, error_message="请求参数错误！"))

        class Carts(object):
            pass

        class Goods(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_cart", "model": Carts},
                {"db_table": "sdet_goods", "model": Goods},
            ]
        )

        open_id = await self.get_open_id()
        cart = session.query(Carts).filter_by(sdef_cart_device_id=open_id).first()
        if not cart:
            session.close()
            return self.write(ret_msg(code=-1, error_message="用户购物车不存在！"))

        cart_goods = json.loads(cart.sdef_cart_goods)
        if not cart_goods:
            session.close()
            return self.write(ret_msg(code=-1, error_message="购物车中没有商品！"))

        for id in id_array:
            for c in cart_goods:
                flag = False
                if c["id"] == id:
                    c["is_buy"] = 1
                    flag = True
                    break

            if not flag:
                session.close()
                return self.write(ret_msg(code=-1, error_message="商品不存在！"))

        for c in cart_goods:
            is_buy = c.get("is_buy", None)
            if not is_buy or c["id"] not in id_array:
                c["is_buy"] = 0

        cart_goods_json = json.dumps(cart_goods)
        session.query(Carts).filter_by(sdef_cart_device_id=open_id).update(
            {Carts.sdef_cart_goods: cart_goods_json}
        )
        session.commit()
        session.close()
        return self.write(ret_msg())


class PayConfirm(ApiBaseHandler):
    def create_coupon_order(
        self, open_id, cu_id, order_id, price_total, coupon_fee, wechat_fee, balance_fee
    ):
        """
        创建优惠券消费记录
        :param open_id:
        :param cu_id:
        :param order_id:
        :param price_total:
        :param coupon_fee:
        :param wechat_fee:
        :param balance_fee:
        :return:
        """

        class CouponUser(object):
            pass

        class Coupon(object):
            pass

        class CouponOrder(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_coupon", "model": Coupon},
                {"db_table": "ebt_coupon_user", "model": CouponUser},
                {"db_table": "ebt_coupon_order", "model": CouponOrder},
            ]
        )

        filters1 = dict(user_id=open_id, coupon_user_id=cu_id, status=0)
        old_co = session.query(CouponOrder).filter_by(**filters1).first()
        if old_co:
            old_order_id = old_co.order_id
            old_co.order_id = order_id
            logger.info(
                f"修改优惠券消费记录成功: open_id={open_id} cu_id={cu_id} old_order_id={old_order_id}"
            )
            session.commit()
            session.close()
            return True

        co = CouponOrder()
        co.user_id = open_id
        co.coupon_user_id = cu_id
        co.order_id = order_id
        co.order_total = price_total
        co.money = coupon_fee
        co.actual_paid = wechat_fee
        co.paid_balance = balance_fee
        co.create_time = datetime.datetime.now()
        co.status = 0
        session.add(co)
        session.commit()
        session.close()
        logger.info(f"创建优惠券使用记录成功order_id={order_id}, oid={open_id}, cu_id={cu_id}")
        return True

    def update_coupons_status(self, cu_id, open_id, order_id):
        class CouponUser(object):
            pass

        class CouponOrder(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_coupon_user", "model": CouponUser},
                {"db_table": "ebt_coupon_order", "model": CouponOrder},
            ]
        )

        filters = dict(
            user_id=open_id, order_id=order_id, status=0, coupon_user_id=cu_id
        )
        co = session.query(CouponOrder).filter_by(**filters).first()
        cu = session.query(CouponUser).filter_by(id=cu_id).first()
        if not co or not cu:
            raise Exception

        co.status = 1
        cu.status = 1
        session.commit()
        session.close()
        return True

    def special_goods_handle(self, cart_goods):
        """特价商品处理"""
        special_id = "575098830553004"  # 第二瓶价格改为0元
        if len(cart_goods) > 1:
            return cart_goods

        goods = list(filter(lambda g: g["id"] == special_id, cart_goods))
        if not goods:
            return cart_goods

        g = goods[0]
        if g["count"] < 2 or g["count"] > 2:
            return cart_goods
        else:
            new_cart_goods = copy.deepcopy(cart_goods)
            g = new_cart_goods[0]
            g["count"] = 1
            g["goods_price"] = Decimal("0.00")
            new_g = copy.deepcopy(g)
            new_cart_goods.append(new_g)
            new_cart_goods[0]["count"] = 1
            new_cart_goods[0]["goods_price"] = Decimal("398.00")
            return new_cart_goods

    def get_delivery_fee(self, order_type, cart_goods_array):
        """
        获取订单运费

        >>> get_delivery_fee(
        ... OrderType.NORMAL,
        ... [
        ...      {
        ...        "id": "496641881103104",
        ...        "count": 1,
        ...        "goods_img": "http://a.cn/a.jpg",
        ...        "goods_name": "wine",
        ...        "goods_price": 49.0,
        ...        "balance_rate": 0.1,
        ...        "unit": 1
        ...      }
        ... ])
        Decimal('15')

        """

        if order_type in [OrderType.BAR, OrderType.PICKUP_IN_STORE, OrderType.MEMBER, OrderType.FREE_CARD, OrderType.MEAL_DEDUCTION]:
            # 小酒馆订单没有运费
            return Decimal(0)

        count = 0
        try:
            for g in cart_goods_array:
                if int(g['unit']) > 99:
                    # 其他单位包邮
                    return Decimal(0)
                if int(g['unit']) >= 6:
                    return Decimal(0)  # 满箱包邮

                count += int(g['count']) * int(g['unit'])
            if count < 6:
                freight = Decimal(15) * Decimal(count)  # 每支加运费15元
                return freight
        except Exception as e:
            logger.error(e)
        return Decimal(0)

    async def get(self):
        open_id = await self.get_open_id()
        t = self.get_parameter("t", None)
        order_type = int(self.get_parameter("type", 1))
        # is_membership = self.is_membership(open_id)
        is_vip = self.is_vip(open_id)
        enable_vip_balance = int(
            self.get_parameter("disable_vip", 0)
        )  # VIP是否使用余额 0=不使用 1=使用 默认为0不使用余额

        is_partner = self.is_partner(open_id)

        old_order_id = None
        message = None

        class Goods(object):
            pass

        class GoodsOrder(object):
            pass

        class Carts(object):
            pass

        class UserAddress(object):
            pass

        class AccountMoney(object):
            pass

        class User(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "sdet_cart", "model": Carts},
                {"db_table": "sdet_address", "model": UserAddress},
                {"db_table": "sdet_order", "model": GoodsOrder},
                {"db_table": "ebt_account_money", "model": AccountMoney},
                {"db_table": "ebt_user", "model": User},
            ]
        )
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if user:
            nickname = user.ebf_user_nickname
            if nickname == "未关注" or nickname == "" or nickname is None:
                await self.update_nickname(open_id)

        cart_goods_array = []
        cart_goods = []
        goods_list = []
        price_total = Decimal(0)
        balance_fee = Decimal(0)
        coupon_fee = Decimal(0)
        forbid_balance_fee = Decimal(0)  # 禁止使用余额的商品金额

        if t == "buy":
            # t=buy表示立刻购买,商品详情页的立即购买链接地址
            goods_id = self.get_parameter("id")
            count = int(self.get_parameter("c", 1))
            cart_goods.append({"id": goods_id, "count": count})
            if goods_id == TI_YAN_GOODS_ID:
                order_type = OrderType.TIYAN
        elif t == "retry":
            # 继续支付
            old_order_id = self.get_parameter("oid", None)
            old_order = (
                session.query(GoodsOrder)
                .filter_by(
                    sdef_order_device_id=open_id,
                    sdef_order_id=old_order_id,
                    sdef_order_is_delete=0,
                )
                .first()
            )
            if not old_order:
                session.close()
                return self.write(ret_msg(code=-1, error_message="订单不存在！"))

            if old_order.sdef_order_status != 1:
                session.close()
                return self.write(ret_msg(code=-1, error_message="只有处于待支付的订单才能继续支付"))

            # 继续支付时解除旧订单锁定的余额
            if old_order.sdef_order_balance_fee > Decimal("0"):
                redis = redis_util.client
                lock_balance_fee = redis.get("balance_lock_%s" % open_id)
                if lock_balance_fee:
                    lock_balance_fee = Decimal(lock_balance_fee.decode())
                    lock_balance_fee -= old_order.sdef_order_balance_fee
                    if lock_balance_fee > Decimal("0"):
                        redis.setex(
                            "balance_lock_%s" % open_id, 600, str(lock_balance_fee)
                        )
                    else:
                        redis.delete("balance_lock_%s" % open_id)

            cart_goods = json.loads(old_order.sdef_order_goods)
            message = old_order.sdef_order_message
            order_type = old_order.sdef_order_type
        elif t == "buy_again":
            # 再次购买
            old_order_id = self.get_parameter("oid", None)
            old_order = (
                session.query(GoodsOrder)
                .filter_by(
                    sdef_order_device_id=open_id,
                    sdef_order_id=old_order_id,
                    sdef_order_is_delete=0,
                )
                .first()
            )
            if not old_order:
                session.close()
                return self.write(ret_msg(code=-1, error_message="订单不存在！"))

            old_fee = (
                old_order.sdef_order_balance_fee
                + old_order.sdef_order_fee
                + old_order.sdef_order_coupon_fee
            )
            if old_fee <= Decimal("0") or old_order.sdef_order_type != 1:
                session.close()
                return self.write(ret_msg(code=-1, error_message="只有普通订单才能再次购买！"))

            cart_goods = json.loads(old_order.sdef_order_goods)
            order_type = old_order.sdef_order_type
        else:
            cart = session.query(Carts).filter_by(sdef_cart_device_id=open_id).first()
            if not cart:
                session.close()
                return self.write(ret_msg(code=-1, error_message="请求参数错误！"))

            old_cart_goods = json.loads(cart.sdef_cart_goods)
            for c in old_cart_goods:
                if c.get("is_buy", None):
                    cart_goods.append(c)

        for c in cart_goods:
            count = int(c["count"])
            goods_id = c["id"]
            _goods = session.query(Goods).filter_by(sdef_goods_id=goods_id).first()
            if not _goods:
                logger.error(f"商品不存在： goods_id={goods_id}")
                continue

            goods_name = _goods.sdef_goods_name

            # 限购逻辑 - 新人礼限购
            if goods_id == promotion.NEW_CUSTOMER_PROMO_GOODS_ID:
                new_customer_gift_order = (
                session.query(GoodsOrder)
                .filter_by(
                    sdef_order_device_id=open_id,
                    sdef_order_pay_status=1,
                    sdef_order_is_delete=0,
                ).filter(
                    GoodsOrder.sdef_order_goods.contains(goods_id)
                )
                .first()
                )
                if new_customer_gift_order:
                    session.close()
                    return self.write(ret_msg(code=-1, error_message=f"{_goods.sdef_goods_name} 已限购，请勿下单"))

            # 定价逻辑
            goods_price = _goods.sdef_goods_price
            balance_rate = _goods.sdef_goods_balance_rate
            # 门店进货订单
            if order_type == OrderType.PINGUI:
                goods_price = _goods.sdef_goods_pin_price
                if not config.IS_BALANCE_AS_CASH:
                    balance_rate = 0
            # 经销商订单/合伙人内供价
            elif order_type == OrderType.DISTRIBUTOR:
                goods_price = _goods.sdef_goods_member_price
                if not config.IS_BALANCE_AS_CASH:
                    balance_rate = 0
            # 礼品订单零售价
            elif order_type == OrderType.GIFT_CARD:
                goods_price = _goods.sdef_goods_price
            # 样品订单
            elif order_type == OrderType.TRIAL:
                if not config.IS_BALANCE_AS_CASH:
                    balance_rate = 0
                is_eligible_for_trial = UserHelper.is_eligible_for_trial(
                    open_id, goods_id
                )
                if not is_eligible_for_trial:
                    return self.write(ret_msg(-1, error_message=f"不能试饮{goods_name}"))
                # 样品价格：经销商价/合伙人价/终端用户价
                if self.is_eligible_for_pin_price(open_id):
                    goods_price = _goods.sdef_goods_pin_price
                elif self.is_eligible_for_member_price(open_id):
                    goods_price = _goods.sdef_goods_member_price
                else:
                    goods_price = _goods.sdef_goods_price
            # 会员价
            elif is_vip and not enable_vip_balance:
                goods_price = _goods.sdef_goods_member_price
                if not config.IS_BALANCE_AS_CASH:
                    balance_rate = 0
            else:
                pass

            goods = dict(
                id=goods_id,
                count=count,
                balance_rate=balance_rate,
                goods_img=json.loads(_goods.sdef_goods_thumbnail)[0],
                goods_name=_goods.sdef_goods_name,
                goods_price=str(goods_price.quantize(Decimal("0.00"))),
                mpq=_goods.sdef_goods_mpq,
                unit=_goods.sdef_goods_unit,
            )
            goods_dict = dict(id=goods_id, count=count)
            balance_fee += Decimal(balance_rate) * Decimal(count) * goods_price
            price_total += goods_price * Decimal(count)
            cart_goods_array.append(goods)
            goods_list.append(goods_dict)
            if balance_rate == 0:
                forbid_balance_fee += goods_price * Decimal(count)
        balance_fee = balance_fee.quantize(Decimal("0.00"))
        max_balance_fee = balance_fee

        default_address = AddressHelper.get_default(open_id)
        use_address = AddressHelper.get_use(open_id)
        db = mongodb_util.db
        address = None
        if use_address:
            logger.debug("使用地址，address_id=%s" % use_address["address_id"])
            address = (
                session.query(UserAddress)
                .filter_by(sdef_address_id=use_address["address_id"])
                .first()
            )
        elif default_address:
            logger.debug("默认地址，address_id=%s" % default_address["address_id"])
            address = (
                session.query(UserAddress)
                .filter_by(sdef_address_id=default_address["address_id"])
                .first()
            )
        else:
            result = db.sdec_address.find(
                {"user_id": open_id, "is_delete": False}
            ).sort("update_time", pymongo.DESCENDING)
            for a in result:
                address = (
                    session.query(UserAddress)
                    .filter_by(sdef_address_id=a["address_id"])
                    .first()
                )
                break
        if not address:
            address_info = {}
        else:
            address_info = dict(
                province=address.sdef_address_province,
                city=address.sdef_address_city,
                county=address.sdef_address_county,
                detail=address.sdef_address_detail,
                name=address.sdef_address_name,
                phone=address.sdef_address_phone,
            )

        # 获取账户余额
        enable_account_money = Decimal(0)
        account_money = (
            session.query(AccountMoney).filter_by(ebf_am_user_id=open_id).first()
        )
        if account_money:
            # 钱包余额需要减去redis缓存中暂扣的金额
            enable_account_money = account_money.ebf_am_money
            redis = redis_util.client
            lock_balance_fee = redis.get("balance_lock_%s" % open_id)
            if lock_balance_fee:
                enable_account_money = Decimal(enable_account_money) - Decimal(
                    lock_balance_fee.decode()
                )

            if account_money.ebf_am_is_forbid == 0 and enable_account_money > 0:
                if enable_account_money < balance_fee:
                    balance_fee = enable_account_money
            else:
                balance_fee = Decimal(0)
            accout_balance = str(account_money.ebf_am_money.quantize(Decimal("0.00")))
        else:
            balance_fee = Decimal(0)
            accout_balance = str(0.00)

        wechat_fee = price_total - balance_fee - coupon_fee
        # 检查支付金额
        if wechat_fee < Decimal("0"):
            logger.error(
                "PAY ERROR: price_total=%s,balance_fee=%s,wechat_fee=%s"
                % (price_total, balance_fee, wechat_fee)
            )
            session.close()
            return self.write(ret_msg(code=-1, error_message="订单支付金额异常"))

        redis = redis_util.client
        unique_str = str(uuid.uuid1())  # 页面唯一字符串，避免多次重复请求，重复支付
        redis.setex("unique_string_%s" % unique_str, 600, 10)
        if enable_account_money < 0:
            enable_account_money = Decimal("0")

        # 店内自提
        # 如果用户在店内扫码，通过动态更新的推荐人获取自提门店编码
        pickup_in_store_id = 0
        store_goods_list = []
        store_agency = UserHelper.get_pickup_store_agency(open_id)  # 店内自提门店
        if store_agency:
            pickup_in_store_id = store_agency.ebf_agency_id
            store_goods_ids = store.get_store_goods_ids(pickup_in_store_id)
            # 获取店内自提商品列表
            store_goods_list = [g for g in goods_list if g["id"] in store_goods_ids]
            # 获取店内自提门店信息
            (
                store_id,
                store_name,
                store_address,
                store_phone,
                store_lng,
                store_lat,
            ) = UserHelper.get_store_info(store_agency)
        if not pickup_in_store_id:
            # 若非店内自提，获取线上门店信息
            (
                store_id,
                store_name,
                store_address,
                store_phone,
                store_lng,
                store_lat,
            ) = UserHelper.get_online_store_info(open_id)
        store_img = f"https://{DOMAIN}/static/img/content/logo-60x60.png"
        if not store_id:
            store_id = 1
            store_name = ""

        delivery_fee = self.get_delivery_fee(order_type, cart_goods_array)

        context = dict(
            store_id=store_id,
            store_address=store_address,
            store_name=store_name,
            store_img=store_img,
            cart_goods_array=cart_goods_array,
            price_total=str(price_total.quantize(Decimal("0.00"))),
            wechat_fee=str(wechat_fee.quantize(Decimal("0.00"))),
            balance_fee=str(balance_fee.quantize(Decimal("0.00"))),  # 抵扣的余额
            max_balance_fee="%.2f" % max_balance_fee,  # 允许的最大支付余额
            able_use_balance_goods_fee="%.2f"
            % (price_total - forbid_balance_fee),  # 判断满减可用券/余额的商品金额
            coupon_fee=int(coupon_fee),
            address=address_info,
            enable_account_money=str(
                enable_account_money.quantize(Decimal("0.00"))
            ),  # 可用余额
            accout_balance=accout_balance,  # 账户余额
            unique_str=unique_str,
            message=message,
            goods_list=goods_list,
            order_type=order_type,
            old_order_id=old_order_id,
            t=t,
            store_goods_list=store_goods_list,  # 客户选择的店内商品列表[{id，count}]
            delivery_fee=str(delivery_fee.quantize((Decimal("0.00")))),  # 订单运费：满6支（1箱）包邮，否则15元/支
        )
        session.close()
        return self.write(ret_msg(data=context))

    async def post(self):
        open_id = await self.get_open_id()
        order_describe = None
        enable_balance_fee = Decimal("0")  # 订单的最大抵扣余额
        is_vip = self.is_vip(open_id)
        is_partner = self.is_partner(open_id)
        ip = self.request.remote_ip

        # is_membership = self.is_membership(open_id)
        pay_type = int(self.get_parameter("pay_type", PayType.WECHAT))
        balance_fee = Decimal(self.get_parameter("balance_fee", "0"))
        # 订单类型（1=普通订单，2=送礼订单，3=加盟费订单，4=特惠订单，5=餐券抵扣订单，6=礼品卡订单，7=新礼品订单，8=体验卡买单订单）
        order_type = int(self.get_parameter("order_type", 1))
        coupon_fee = Decimal(self.get_parameter("coupon_fee", "0"))
        message = self.get_parameter("message", "")
        url = self.get_parameter("url", None)  # 用户请求该接口前所在的页面完整地址
        cu_id = int(self.get_parameter("cu_id", 0))
        disable_vip = int(self.get_parameter("disable_vip", 0))  # 禁用VIP价格
        t = self.get_parameter("t", None)
        old_order_id = self.get_parameter("oid", None)
        article_id = self.get_parameter("article_id", None)  # 推荐文章ID
        logger.info(f"article_id={article_id}")

        if pay_type not in [PayType.WECHAT, PayType.BALANCE]:
            return self.write(ret_msg(code=-1, error_message="目前只支持微信支付和余额支付"))

        if t == "retry" or t == "buy_again":
            if not old_order_id:
                return self.write(ret_msg(code=-1, error_message="缺少请求参数订单编号"))

        if order_type != OrderType.MEMBER:
            unique_str = self.get_parameter("unique_str")
            redis = redis_util.client
            unique_string = redis.get("unique_string_%s" % unique_str)
            if not unique_string:
                return self.write(ret_msg(code=-1, error_message="页面已失效，请返回购物车重新下单！"))

        if cu_id and balance_fee > 0:
            return self.write(ret_msg(code=-1, error_message="优惠券和余额不能同时使用！"))

        # is_pingui_power = is_have_pingui_power(open_id)
        # if order_type == OrderType.PINGUI and not is_pingui_power:
        #     return self.write(ret_msg(code=-1, error_message="没有拼柜权限！"))

        class UserAddress(object):
            pass

        class GoodsOrder(object):
            pass

        class Goods(object):
            pass

        class Carts(object):
            pass

        class User(object):
            pass

        class AccountMoney(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "sdet_cart", "model": Carts},
                {"db_table": "sdet_order", "model": GoodsOrder},
                {"db_table": "sdet_address", "model": UserAddress},
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_account_money", "model": AccountMoney},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user_agency", "model": UserAgency},
            ]
        )

        if order_type == OrderType.MEMBER:
            fee = Decimal(self.get_parameter("fee", 0))
            num = int(self.get_parameter("num", 1))
            type = int(
                self.get_parameter("type", 0)
            )  # type=0表示"线上分享", 1表示"托管经营", 2表示"线下开店" 3为"联营店主注册"
            unit = Decimal("2499")
            pay_fee = Decimal(unit * num)
            if not type and fee != Decimal("980") and fee != Decimal("499"):
                return self.write(ret_msg(code=-1, error_message="支付金额错误"))

            if type < 3:
                logger.info("fee=%s, pay_fee=%s" % (fee, pay_fee))
                if fee != pay_fee:
                    return self.write(ret_msg(code=-1, error_message="支付金额与数目不匹配"))

            now = datetime.datetime.now()
            order = GoodsOrder()
            out_trade_no = generator_trade_no()
            order.sdef_order_id = out_trade_no
            order.sdef_order_factory_uid = FACTORY_UID
            order.sdef_order_device_id = open_id
            order.sdef_order_fee = fee
            order.sdef_order_name = "思达尔加盟费"
            order.sdef_order_type = OrderType.MEMBER
            order.sdef_order_pay_type = pay_type
            order.sdef_order_ip = ip
            order.sdef_order_delivery_fee = 0  # 邮费
            order.sdef_order_create_time = now
            if type == 0:
                order_describe = "online" + str(num)
                order.sdef_order_describe = order_describe  # 线上分享
                order.sdef_order_message = "1"  # 不需要每日返还收益标志
            elif type == 1:
                order_describe = "crowdfunding"
                order.sdef_order_describe = order_describe  # 托管经营
            elif type == 2:
                order_describe = "underline"
                order.sdef_order_describe = order_describe  # 线下开店
                order.sdef_order_message = "1"  # 不需要每日返还收益标志
            elif type == 3:
                order_describe = "联营店主注册"
                order.sdef_order_describe = order_describe  # 线下开店
                order.sdef_order_message = "1"  # 不需要每日返还收益标志
            else:
                session.close()
                return self.write(ret_msg(code=-1, error_message="不支持的分享类型！"))

            if pay_type == PayType.WECHAT:
                order.sdef_order_status = OrderStatus.WAIT_PAY
                order.sdef_order_pay_status = PayStatus.NOT_PAY
            else:
                return self.write(ret_msg(code=-1, error_message="请使用微信支付！"))

            user = session.query(User).filter_by(ebf_user_id=open_id).first()
            user_agency = (
                session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()
            )
            agency = (
                session.query(Agency)
                .filter_by(ebf_agency_id=user_agency.ebf_agency_id)
                .first()
            )
            agency_uid = agency.ebf_agency_uid
            if user and user.ebf_user_agency_uid != agency_uid:
                user.ebf_user_agency_uid = agency_uid

            order.sdef_order_agency_uid = agency_uid
            session.add(order)
            inviter_oid = self.get_parameter("inviter_oid", None)
            logger.info(
                "inviter_oid=%s, oid=%s, order_id=%s"
                % (inviter_oid, open_id, out_trade_no)
            )
            recommend_user = user.ebf_user_recommend_user

            if inviter_oid and recommend_user != inviter_oid and inviter_oid != open_id:
                user.ebf_user_recommend_user = inviter_oid
                msg = "更新推荐人: recommend_user={}, inviter_oid={}, oid={}, order_id={}"
                logger.info(
                    msg.format(recommend_user, inviter_oid, open_id, out_trade_no)
                )
        else:
            default_address = AddressHelper.get_default(open_id)
            use_address = AddressHelper.get_use(open_id)
            db = mongodb_util.db
            address = None
            if use_address:
                logger.debug("使用地址，address_id=%s" % use_address["address_id"])
                address = (
                    session.query(UserAddress)
                    .filter_by(sdef_address_id=use_address["address_id"])
                    .first()
                )
            elif default_address:
                logger.debug("默认地址，address_id=%s" % default_address["address_id"])
                address = (
                    session.query(UserAddress)
                    .filter_by(sdef_address_id=default_address["address_id"])
                    .first()
                )
            else:
                result = db.sdec_address.find(
                    {"user_id": open_id, "is_delete": False}
                ).sort("update_time", pymongo.DESCENDING)
                for a in result:
                    address = (
                        session.query(UserAddress)
                        .filter_by(sdef_address_id=a["address_id"])
                        .first()
                    )
                    if address:
                        break

            # 送礼订单/自提订单允许地址为空
            if not address and order_type not in [OrderType.GIFT, OrderType.PICKUP_IN_STORE]:
                session.close()
                return self.write(ret_msg(code=-1, error_message="请先完善收货地址"))

            cart_goods = self.get_parameter("goods_list", [])
            cart_goods_array = []
            price_total = Decimal("0")
            freight = Decimal("0")
            forbid_balance_fee = Decimal(0)  # 禁止使用余额的商品金额
            if not cart_goods:
                session.close()
                return self.write(ret_msg(-1, error_message="请返回购物车或商城选择要购买的商品！"))

            if not isinstance(cart_goods, list):
                cart_goods = json.loads(cart_goods)

            if (
                config.TI_YAN_GOODS_ID in json.dumps(cart_goods)
                and len(cart_goods) != 1
            ):
                session.close()
                return self.write(ret_msg(-1, error_message="体验商品不能跟其他商品一起购买！"))

            for c in cart_goods:
                goods_id = c["id"]
                count = int(c["count"])
                _goods = (
                    session.query(Goods)
                    .filter_by(sdef_goods_id=c["id"], sdef_goods_is_delete=0)
                    .first()
                )
                if not _goods:
                    logger.error(f"商品不存在： goods_id={goods_id}")
                    session.close()
                    return self.write(ret_msg(-1, error_message="商品不存在"))

                if _goods.sdef_goods_status != 1 and c["id"] != "562225951936393":
                    session.close()
                    return self.write(ret_msg(-1, error_message="商品已下架"))

                if goods_id == TI_YAN_GOODS_ID and count != 1:
                    session.close()
                    return self.write(ret_msg(-1, error_message="体验商品数量只能选择一件"))

                goods_name = _goods.sdef_goods_name
                goods_img = json.loads(_goods.sdef_goods_thumbnail)[0]

                # 定价逻辑
                goods_price = _goods.sdef_goods_price
                balance_rate = _goods.sdef_goods_balance_rate
                # 门店进货订单
                if order_type == OrderType.PINGUI:
                    goods_price = _goods.sdef_goods_pin_price
                    if not config.IS_BALANCE_AS_CASH:
                        balance_rate = 0
                # 经销商订单/合伙人内供价
                elif order_type == OrderType.DISTRIBUTOR:
                    goods_price = _goods.sdef_goods_member_price
                    if not config.IS_BALANCE_AS_CASH:
                        balance_rate = 0
                # 礼品订单零售价
                elif order_type == OrderType.GIFT_CARD:
                    goods_price = _goods.sdef_goods_price
                # 样品订单
                elif order_type == OrderType.TRIAL:
                    if not config.IS_BALANCE_AS_CASH:
                        balance_rate = 0
                    is_eligible_for_trial = UserHelper.is_eligible_for_trial(
                        open_id, goods_id
                    )
                    if not is_eligible_for_trial:
                        return self.write(
                            ret_msg(-1, error_message=f"不能试饮{goods_name}")
                        )
                    # 样品价格：经销商价/合伙人价/终端用户价
                    if self.is_eligible_for_pin_price(open_id):
                        goods_price = _goods.sdef_goods_pin_price
                    elif self.is_eligible_for_member_price(open_id):
                        goods_price = _goods.sdef_goods_member_price
                    else:
                        goods_price = _goods.sdef_goods_price
                # 会员价
                elif is_vip and not disable_vip:
                    goods_price = _goods.sdef_goods_member_price
                    if not config.IS_BALANCE_AS_CASH:
                        balance_rate = 0
                else:
                    pass

                # 检查商品是否限购
                if _goods.sdef_goods_limit_num != 0:
                    if _goods.sdef_goods_limit_num < count:
                        goods_limit_num = _goods.sdef_goods_limit_num
                        return self.write(
                            ret_msg(
                                -1, error_message=f"{goods_name}超出限购数量{goods_limit_num}"
                            )
                        )

                if t != "retry":
                    # 下单时减少库存
                    if _goods.sdef_goods_count >= count:
                        logger.info(
                            f"old_goods_count={_goods.sdef_goods_count} count={count}"
                        )
                        _goods.sdef_goods_count -= count
                    else:
                        session.close()
                        return self.write(
                            ret_msg(-1, error_message=f"{goods_name}商品库存不足")
                        )

                goods = dict(
                    id=goods_id,
                    count=count,
                    goods_img=goods_img,
                    goods_name=_goods.sdef_goods_name,
                    goods_price=goods_price,
                    goods_member_price=_goods.sdef_goods_member_price,
                    goods_pin_price=_goods.sdef_goods_pin_price,
                    balance_rate=balance_rate,
                    rate=_goods.sdef_goods_rate,
                    master_rate=_goods.sdef_goods_master_rate,
                    invite_rate=_goods.sdef_goods_invite_rate,
                    invite_invite_rate=_goods.sdef_goods_invite_invite_rate,
                    career_rate=_goods.sdef_goods_career_rate,
                    invite_career_rate=_goods.sdef_goods_invite_career_rate,
                    supplier=_goods.sdef_goods_supplier,
                    goods_cost=_goods.sdef_goods_cost,
                    unit=_goods.sdef_goods_unit,
                )
                enable_balance_fee += (
                    Decimal(balance_rate) * Decimal(count) * goods_price
                )
                price_total += goods_price * Decimal(count)

                # 计算门店进货运费6元/支
                if order_type == OrderType.PINGUI:
                    freight += Decimal("6.00") * Decimal(count)

                cart_goods_array.append(goods)
                if balance_rate == 0:
                    forbid_balance_fee += goods_price * Decimal(count)
            max_deductible_fee = enable_balance_fee.quantize(
                Decimal("0.00")
            )  # 最大允许抵扣金额(余额+券）
            
            # 处理运费
            freight = self.get_delivery_fee(order_type, cart_goods_array)
            if freight:
                price_total += freight

            if order_type == OrderType.PINGUI:
                service_fee = ApiHelper.service_fee(price_total)
                price_total += service_fee

            enable_balance_fee = enable_balance_fee.quantize(Decimal("0.00"))
            # 获取账户余额
            account_money = (
                session.query(AccountMoney).filter_by(ebf_am_user_id=open_id).first()
            )
            lock_balance_fee = redis.get("balance_lock_%s" % open_id)
            if account_money:
                # 钱包余额需要减去redis缓存中暂扣的金额
                enable_account_money = account_money.ebf_am_money

                if lock_balance_fee:
                    enable_account_money = Decimal(enable_account_money) - Decimal(
                        lock_balance_fee.decode()
                    )

                if (
                    account_money
                    and account_money.ebf_am_is_forbid == 0
                    and enable_account_money > 0
                ):
                    if enable_account_money < enable_balance_fee:
                        enable_balance_fee = enable_account_money
                else:
                    enable_balance_fee = Decimal("0")
            else:
                enable_balance_fee = Decimal("0")

            if enable_balance_fee < balance_fee:
                logger.error(
                    f"enable_balance_fee={enable_balance_fee} balance_fee={balance_fee}"
                )
                session.close()
                return self.write(ret_msg(code=-1, error_message="可抵扣余额错误"))

            # 检查优惠券
            able_use_balance_goods_fee = (
                price_total - forbid_balance_fee
            )  # 判断满减:可用券/余额的商品金额(扣除禁止用券商品金额）
            if cu_id:
                is_use_coupon = get_available_coupons(
                    0,
                    order_type,
                    open_id,
                    able_use_balance_goods_fee,
                    cart_goods,
                    10,
                    0,
                    cu_id=cu_id,
                )
                if not is_use_coupon:
                    session.close()
                    return self.write(ret_msg(code=-1, error_message="优惠券ID错误"))

                real_coupon_fee = is_use_coupon[0]["coupon_money"]
                if coupon_fee > real_coupon_fee:
                    session.close()
                    return self.write(ret_msg(code=-1, error_message="优惠券金额错误"))

            if is_vip and not disable_vip:
                # 是vip且没有禁用vip价格不能使用优惠券和余额
                balance_fee = Decimal("0")
                coupon_fee = Decimal("0")

            special_cart_goods = self.special_goods_handle(cart_goods_array)
            if len(special_cart_goods) != len(cart_goods_array):
                price_total = Decimal("398.00")
                cart_goods_array = special_cart_goods

            #  优惠券使用金额和余额金额不能超过允许的最大抵扣金额
            if coupon_fee + balance_fee > max_deductible_fee:
                adjusted_coupon_fee = max_deductible_fee - balance_fee
                logger.error(f"优惠券金额{coupon_fee}调整为{adjusted_coupon_fee}")
                coupon_fee = adjusted_coupon_fee
                if coupon_fee < Decimal("0"):
                    coupon_fee = Decimal("0")
                    logger.error(f"优惠券金额归0")

            wechat_fee = price_total - balance_fee - coupon_fee
            logger.info(
                "price_total=%s,balance_fee=%s,wechat_fee=%s"
                % (price_total, balance_fee, wechat_fee)
            )
            # 检查支付金额
            if wechat_fee < Decimal("0"):
                logger.error(
                    "PAY ERROR: price_total=%s,balance_fee=%s,wechat_fee=%s"
                    % (price_total, balance_fee, wechat_fee)
                )
                session.close()
                return self.write(ret_msg(code=-1, error_message="订单支付金额异常"))

            if coupon_fee > Decimal("0"):
                if wechat_fee <= Decimal("0") and balance_fee == Decimal("0"):
                    pay_type = PayType.COUPON  # 支付方式标记为优惠券抵扣
            elif wechat_fee < Decimal("0.01"):
                pay_type = PayType.BALANCE  # 支付方式直接标记为余额支付
            else:
                pass

            now = datetime.datetime.now()
            out_trade_no = generator_trade_no()
            goods_order = GoodsOrder()
            goods_order.sdef_order_id = out_trade_no
            goods_order.sdef_order_factory_uid = FACTORY_UID
            goods_order.sdef_order_device_id = open_id  # 微信用户openId
            goods_order.sdef_order_fee = wechat_fee
            goods_order.sdef_order_goods = json.dumps(cart_goods_array, cls=JSONEncoder)
            goods_order.sdef_order_balance_fee = balance_fee
            goods_order.sdef_order_name = "思达尔商城订单"
            goods_order.sdef_order_message = message
            goods_order.sdef_order_coupon_fee = coupon_fee
            goods_order.sdef_order_describe = "微信商城订单"

            if pay_type == PayType.WECHAT:
                goods_order.sdef_order_status = OrderStatus.WAIT_PAY
                goods_order.sdef_order_pay_status = PayStatus.NOT_PAY
            else:
                goods_order.sdef_order_status = OrderStatus.WAIT_EXPRESS
                goods_order.sdef_order_pay_status = PayStatus.SUCCESS
                goods_order.sdef_order_pay_time = now

            if article_id:
                goods_order.sdef_order_recommend_id = article_id

            goods_order.sdef_order_pay_type = pay_type
            goods_order.sdef_order_type = order_type
            # 送礼订单不需要地址
            if order_type not in [OrderType.GIFT]:
                goods_order.sdef_order_address_id = address.sdef_address_id

            goods_order.sdef_order_ip = ip
            goods_order.sdef_order_delivery_fee = freight  # 邮费
            goods_order.sdef_order_create_time = now
            # 获取当前用户所属的合伙人填入订单中（没有合伙人的使用默认合伙人的uid）
            agency_uid = config.DEFAULT_AGENCY_UID
            users = session.query(User).filter_by(ebf_user_id=open_id).all()
            if len(users) == 1:
                user = users[0]
                if user.ebf_user_agency_uid:
                    agency_uid = user.ebf_user_agency_uid

            goods_order.sdef_order_agency_uid = agency_uid
            session.add(goods_order)

            if coupon_fee > Decimal("0"):
                self.create_coupon_order(
                    open_id,
                    cu_id,
                    out_trade_no,
                    price_total,
                    coupon_fee,
                    wechat_fee,
                    balance_fee,
                )

            redis = redis_util.client
            redis.setex("order_id_%s" % out_trade_no, 86400, out_trade_no)

            if t == "buy":
                pass
            elif t == "pickup_in_store":
                pass
            elif t == "retry":
                logger.info("old_order_id=%s" % old_order_id)
                old_order = (
                    session.query(GoodsOrder)
                    .filter_by(
                        sdef_order_device_id=open_id,
                        sdef_order_id=old_order_id,
                        sdef_order_is_delete=0,
                    )
                    .first()
                )

                if old_order.sdef_order_status != OrderStatus.WAIT_PAY:
                    session.close()
                    return self.write(
                        ret_msg(code=-1, error_message="只有处于待支付的订单才能继续支付")
                    )

                # 获取之前的支付信息，创建完新订单之后将之前的订单标记为删除
                old_order.sdef_order_is_delete = 1
                old_order.sdef_order_delete_time = datetime.datetime.now()
                old_order.sdef_order_status = OrderStatus.INVALID
                logger.debug("将旧订单标记为删除：%s" % old_order_id)
            elif t == "buy_again":
                pass
            else:
                # 并清空购物车
                cart = (
                    session.query(Carts).filter_by(sdef_cart_device_id=open_id).first()
                )
                if not cart:
                    session.close()
                    return self.write(ret_msg(-1, error_message="购物车不存在！"))

                new_cart_goods = []
                old_cart_goods = json.loads(cart.sdef_cart_goods)
                if len(old_cart_goods) == len(cart_goods):
                    ret = (
                        session.query(Carts)
                        .filter_by(sdef_cart_device_id=open_id)
                        .delete()
                    )
                else:
                    ret = 0
                    for c in old_cart_goods:
                        if not c.get("is_buy", None):
                            new_cart_goods.append(c)

                    session.query(Carts).filter_by(sdef_cart_device_id=open_id).update(
                        {Carts.sdef_cart_goods: json.dumps(new_cart_goods)}
                    )

                logger.info("delete cart ret=%s" % ret)

            redis.delete("unique_string_%s" % unique_str)
            if pay_type == PayType.BALANCE:
                logger.info("余额支付")
                account_money = (
                    session.query(AccountMoney)
                    .filter_by(ebf_am_user_id=open_id)
                    .first()
                )
                if not account_money:
                    session.close()
                    return self.write(ret_msg(-1, error_message="账户未开通"))

                if account_money.ebf_am_is_forbid != 0:
                    session.close()
                    return self.write(ret_msg(-1, error_message="账户不可用"))

                if account_money.ebf_am_money < price_total:
                    session.close()
                    return self.write(ret_msg(-1, error_message="账户余额不足"))
                # 计算提成金额
                # 余额的不分成时 可以通过后台将余额的分成比例设为0来解决
                price_total_rate = calculate_order_fee(goods_order.sdef_order_goods)[0]
                # 扣款并添加扣款记录，同时往ebt_pay表中添加一条订单
                if not BalanceHandler.reduce_money(
                    open_id, out_trade_no, price_total, price_total_rate, ip
                ):
                    session.close()
                    return self.write(ret_msg(-1, error_message="扣款失败"))

                is_success = create_balance_record(open_id, price_total, out_trade_no)
                if is_success:
                    logger.info(
                        "创建余额消费记录成功:user_id=%s,out_trade_no=%s"
                        % (open_id, out_trade_no)
                    )
                else:
                    logger.error(
                        "创建余额消费记录失败:user_id=%s,out_trade_no=%s"
                        % (open_id, out_trade_no)
                    )

                context = dict(trade_no=out_trade_no, pay_type=pay_type)
                session.commit()
                # 触发订单支付成功异步事件 - 收益计算/通知
                tasks.order_paid.delay(out_trade_no)
                session.close()
                return self.write(ret_msg(data=context))

            if pay_type == PayType.COUPON:
                logger.info(
                    f"优惠券抵扣: order_id={out_trade_no}, cu_id={cu_id}, oid={open_id}"
                )
                self.update_coupons_status(cu_id, open_id, out_trade_no)
                logger.info(f"触发纯优惠券支付成功异步任务 order_id={out_trade_no}")
                tasks.order_paid.delay(out_trade_no)
                session.commit()
                session.close()
                context = dict(trade_no=out_trade_no, pay_type=PayType.COUPON)
                return self.write(ret_msg(data=context))

        try:
            session.commit()
        except Exception as e:
            logger.exception(e)
            session.rollback()
            session.close()
            return self.write(ret_msg(code=-1, error_message="订单创建异常"))

        app_id = MP_APP_ID
        time_stamp = int(str(time.time()).split(".")[0])
        nonce_str = WechatPay.generate_nonce_str()
        # 生成预支付交易单
        logger.info("生成预支付交易单")

        if order_type == OrderType.MEMBER:
            try:
                prepay_id = WechatPay.order(
                    out_trade_no, int(fee * 100), "加盟费订单", ip, nonce_str, open_id
                )
            except Exception as e:
                logger.exception(e)
                session.close()
                return self.finish(ret_msg(code=-1, error_message="支付异常"))
        else:
            try:
                prepay_id = WechatPay.order(
                    out_trade_no, int(wechat_fee * 100), "商城订单", ip, nonce_str, open_id
                )

                # 将暂扣的余额存入redis中，超时时间10分钟，微信支付回调时直接扣余额即可
                if lock_balance_fee:
                    lock_balance_fee = Decimal(lock_balance_fee.decode()) + balance_fee
                else:
                    lock_balance_fee = balance_fee
                redis.setex("balance_lock_%s" % open_id, 600, str(lock_balance_fee))

                if use_address:
                    if default_address:
                        if use_address["address_id"] != default_address["address_id"]:
                            is_default = True
                            is_use = True
                            AddressHelper.set_default(
                                open_id,
                                default_address["address_id"],
                                is_default,
                                is_use,
                            )
                    else:
                        is_default = False
                        is_use = False
                        AddressHelper.set_default(
                            open_id, use_address["address_id"], is_default, is_use
                        )
            except Exception as e:
                logger.exception(e)
                session.close()
                return self.finish(ret_msg(code=-1, error_message="支付异常"))

        package = "prepay_id=" + prepay_id
        # 计算jsapi签名
        logger.info("计算jsapi签名" + package)
        sign_value = WechatPay.get_jsapi_pay_sign(time_stamp, nonce_str, package, "MD5")
        jsapi_ticket = self.get_jsapi_ticket()
        signature = Wechat_Base.signature(nonce_str, time_stamp, url, jsapi_ticket)
        logger.debug("signature：%s url: %s" % (signature, url))

        # 微信支付的加入消息队列，6分钟后检查是否已支付
        add_mq_task(out_trade_no, message_type=1, delay=360)
        # 如果是礼品订单/礼品卡订单，则在24小时后检查是否需要退款
        if order_type in [OrderType.GIFT, OrderType.GIFT_CARD]:
            add_mq_task(out_trade_no, message_type=2, delay=GIFT_ORDER_REFUND_TIMEOUT)

        context = dict(
            trade_no=out_trade_no,
            app_id=app_id,
            time_stamp=str(time_stamp),
            nonce_str=nonce_str,
            sign_value=sign_value,
            prepay_id=prepay_id,
            signature=signature,
            full_url=url,
            order_type=order_type,
            pay_type=pay_type,
            describe=order_describe,
        )
        session.close()
        return self.write(ret_msg(data=context))


class BalanceDetail(ApiBaseHandler):
    async def get(self):
        open_id = await self.get_open_id()

        class Pay(object):
            pass

        class GoodsOrder(object):
            pass

        class ChargeRecord(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_pay", "model": Pay},
                {"db_table": "sdet_order", "model": GoodsOrder},
                {"db_table": "ebt_charge_record", "model": ChargeRecord},
            ]
        )

        time_range = self.get_parameter("time_range", None)
        page_index = int(self.get_parameter("page_index", 0))
        page_size = int(self.get_parameter("page_size", 10))
        ApiHelper.inspect_common_params(page_index, page_size)
        page_start = page_index * page_size
        id = self.get_parameter("id", None)
        # 按余额记录类型查找（1="消费订单", 2="账户充值订单"）
        type = self.get_parameter("type", None)

        balances = None
        filters = dict(
            ebf_user_id=open_id,
            # ebf_pay_is_success=1,
            # ebf_pay_status=1,
            ebf_pay_factory_id=config.FACTORY_ID,
        )

        if id:
            id = int(id)
            balances = (
                session.query(Pay).filter_by(ebf_pay_id=id, ebf_user_id=open_id).all()
            )
            if not balances:
                session.close()
                return self.write(ret_msg(code=-1, error_message="该余额记录不存在"))

        else:
            if time_range:
                start_time, end_time = ApiHelper.get_time_range(time_range)
            else:
                day_now = time.localtime()
                day_begin = "%d-%02d-01 00:00:00" % (day_now.tm_year, day_now.tm_mon)
                wday, month_range = calendar.monthrange(day_now.tm_year, day_now.tm_mon)
                day_end = "%d-%02d-%02d 23:59:59" % (
                    day_now.tm_year,
                    day_now.tm_mon,
                    month_range,
                )
                time_range = "~".join([day_begin, day_end])
                start_time, end_time = ApiHelper.get_time_range(time_range)
            pay = (
                session.query(func.sum(Pay.ebf_pay_fee))
                .filter_by(**filters)
                .filter(Pay.ebf_pay_create_date >= start_time)
                .filter(Pay.ebf_pay_create_date <= end_time)
                .filter(or_(Pay.ebf_pay_content != "微信支付", Pay.ebf_pay_content == None))
                .filter_by(ebf_pay_trade_type=1)
                .scalar()
            )
            income = (
                session.query(func.sum(Pay.ebf_pay_fee))
                .filter_by(**filters)
                .filter(Pay.ebf_pay_create_date >= start_time)
                .filter(Pay.ebf_pay_create_date <= end_time)
                .filter(or_(Pay.ebf_pay_content != "微信支付", Pay.ebf_pay_content == None))
                .filter_by(ebf_pay_trade_type=2)
                .scalar()
            )
            pay = str(pay.quantize(Decimal("0.00"))) if pay else "0.00"
            income = str(income.quantize(Decimal("0.00"))) if income else "0.00"

            if type:
                filters["ebf_pay_trade_type"] = int(type)

            balances = (
                session.query(Pay)
                .filter_by(**filters)
                .filter(Pay.ebf_pay_create_date >= start_time)
                .filter(Pay.ebf_pay_create_date <= end_time)
                .filter(or_(Pay.ebf_pay_content != "微信支付", Pay.ebf_pay_content == None))
                .order_by(Pay.ebf_pay_id.desc())[page_start : page_start + page_size]
            )

            if not balances:
                context = dict(
                    pay="0.00",
                    income="0.00",
                )
                session.close()
                return self.write(ret_msg(data=context))

        bl_list = []
        for bl in balances:
            if bl.ebf_pay_type == 1:
                _pay_type = "支付宝"
            elif bl.ebf_pay_type == 2:
                _pay_type = "微信支付"
            elif bl.ebf_pay_type == 3:
                _pay_type = "银联"
            elif bl.ebf_pay_type == 4:
                _pay_type = "账户余额"
            elif bl.ebf_pay_type == 5:
                _pay_type = "人工充值"
            elif bl.ebf_pay_type == 6:
                _pay_type = "合伙人注册充值"
            else:
                _pay_type = "未知"

            if bl.ebf_pay_status == -1:
                _pay_status = "支付失败"
            elif bl.ebf_pay_status == 0:
                _pay_status = "等待付款"
            elif bl.ebf_pay_status == 1:
                _pay_status = "支付成功"
            elif bl.ebf_pay_status == 2:
                _pay_status = "人工退款"
            elif bl.ebf_pay_status == 3:
                _pay_status = "取消支付"
            elif bl.ebf_pay_status == 4:
                _pay_status = "自动退款"
            elif bl.ebf_pay_status == 5:
                _pay_status = "对账异常"
            else:
                _pay_status = "未知"

            if bl.ebf_pay_trade_type == 1:
                _trade_type = "消费订单"
            elif bl.ebf_pay_trade_type == 2:
                _trade_type = "账户充值订单"
            else:
                _trade_type = "未知"

            bl_dict = dict(
                id=bl.ebf_pay_id,
                trade_no=bl.ebf_pay_trade_no,
                fee=str(bl.ebf_pay_fee.quantize(Decimal("0.00"))),
                create_date=bl.ebf_pay_create_date.strftime(
                    "%Y{y}%m{m}%d{d} %H:%M:%S"
                ).format(y="年", m="月", d="日"),
                pay_date=bl.ebf_pay_pay_date.strftime(
                    "%Y{y}%m{m}%d{d} %H:%M:%S"
                ).format(y="年", m="月", d="日"),
                pay_type=bl.ebf_pay_type,
                per_pay_type=_pay_type,
                pay_content=bl.ebf_pay_content,
                pay_status=bl.ebf_pay_status,
                per_pay_status=_pay_status,
                pay_account=bl.ebf_pay_account,
                agency_id=bl.ebf_pay_agency_id,
                trade_type=bl.ebf_pay_trade_type,
                per_trade_type=_trade_type,
            )
            bl_list.append(bl_dict)
        context = {}
        if not id:
            context["pay"] = pay  # 当月余额支出
            context["income"] = income  # 当月余额收入
        context["balance"] = bl_list
        session.close()
        return self.write(ret_msg(data=context))


class ReportUser(ApiBaseHandler):
    async def get(self):
        class User(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        class Benefit(object):
            pass

        class Order(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user_agency", "model": UserAgency},
                {"db_table": "sdet_benefit", "model": Benefit},
                {"db_table": "sdet_order", "model": Order},
            ]
        )

        time_range = self.get_parameter("time_range", None)
        page_index = int(self.get_parameter("page_index", 0))
        page_size = int(self.get_parameter("page_size", 10))
        ApiHelper.inspect_common_params(page_index, page_size)
        page_start = page_index * page_size

        if time_range:
            start_time, end_time = ApiHelper.get_time_range(time_range)
        else:
            start_time = datetime.datetime(2015, 1, 1, 0, 0, 0)
            end_time = datetime.datetime.now()

        # 用户按消费从大到小排序
        order_list = (
            session.query(
                Order.sdef_order_device_id,
                func.sum(Order.sdef_order_fee + Order.sdef_order_balance_fee),
            )
            .filter_by(sdef_order_status=4)
            .filter(Order.sdef_order_type < 3)
            .filter(Order.sdef_order_create_time >= start_time)
            .filter(Order.sdef_order_create_time <= end_time)
            .group_by(Order.sdef_order_device_id)
            .order_by(
                func.sum(Order.sdef_order_fee + Order.sdef_order_balance_fee).desc()
            )[page_start : page_start + page_size]
        )

        context = []
        for open_id, total_fee in order_list:
            user = session.query(User).filter_by(ebf_user_id=open_id).first()
            if not user:
                continue

            if user.ebf_user_gender == 1:
                _gender = "男"
            elif user.ebf_user_gender == 2:
                _gender = "女"
            else:
                _gender = "未知"

            user_info = dict(
                total_fee=str(total_fee.quantize(Decimal("0.00"))),
                open_id=open_id,
                nickname=user.ebf_user_nickname,
                headurl=user.ebf_user_headurl,
                gender=_gender,
            )
            context.append(user_info)
        session.close()
        return self.write(ret_msg(data=context))


class ReportPartner(ApiBaseHandler):
    async def get(self):
        class User(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        class Benefit(object):
            pass

        class Order(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user_agency", "model": UserAgency},
                {"db_table": "sdet_benefit", "model": Benefit},
                {"db_table": "sdet_order", "model": Order},
            ]
        )

        time_range = self.get_parameter("time_range", None)
        page_index = int(self.get_parameter("page_index", 0))
        page_size = int(self.get_parameter("page_size", 10))
        ApiHelper.inspect_common_params(page_index, page_size)
        page_start = page_index * page_size
        agency_type = self.get_parameter("type", "")

        if time_range:
            start_time, end_time = ApiHelper.get_time_range(time_range)
        else:
            start_time = datetime.datetime(2015, 1, 1, 0, 0, 0)
            end_time = datetime.datetime.now()

        if agency_type:
            # 高级合伙人或者事业合伙人收益排名
            if agency_type == "1" or agency_type == "2":
                if agency_type == "1":
                    type = "高级合伙人"
                    filter = dict(
                        ebf_agency_type=1,
                    )
                elif agency_type == "2":
                    type = "事业合伙人"
                    filter = dict(
                        ebf_agency_type=2,
                    )

                partner_nums = (
                    session.query(func.count(Agency.ebf_agency_id))
                    .filter_by(**filter)
                    .scalar()
                )
                item = (
                    session.query(Agency.ebf_agency_uid)
                    .filter(Agency.ebf_agency_type == int(agency_type))
                    .subquery()
                )
                result = (
                    session.query(Benefit.agency_uid, func.sum(Benefit.fee))
                    .filter_by(status=1, is_valid=1, is_finish=1)
                    .filter(Benefit.create_time >= start_time)
                    .filter(Benefit.create_time <= end_time)
                    .join(item, Benefit.agency_uid == item.c.ebf_agency_uid)
                    .group_by(Benefit.agency_uid)
                    .order_by(func.sum(Benefit.fee).desc())[
                        page_start : page_start + page_size
                    ]
                )
            else:
                session.close()
                return self.write(ret_msg(code=-1, error_message="没有此类型合伙人"))

        else:
            # 所有合伙人收益排名
            partner_nums = session.query(func.count(Agency.ebf_agency_id)).scalar()

            result = (
                session.query(Benefit.agency_uid, func.sum(Benefit.fee))
                .filter_by(status=1, is_valid=1, is_finish=1)
                .filter(Benefit.create_time >= start_time)
                .filter(Benefit.create_time <= end_time)
                .group_by(Benefit.agency_uid)
                .order_by(func.sum(Benefit.fee).desc())[
                    page_start : page_start + page_size
                ]
            )

        context = []
        for agency_uid, total_benefit in result:
            agency = session.query(Agency).filter_by(ebf_agency_uid=agency_uid).first()
            if not agency:
                continue
            ua = (
                session.query(UserAgency)
                .filter_by(ebf_agency_id=agency.ebf_agency_id)
                .first()
            )
            user = None
            if ua:
                user = (
                    session.query(User)
                    .filter_by(ebf_user_id=ua.ebf_ua_bind_user_id)
                    .first()
                )

            if not agency_type:
                if agency.ebf_agency_type == 1:
                    type = "高级合伙人"
                elif agency.ebf_agency_type == 2:
                    type = "事业合伙人"
                else:
                    type = "合伙人"

            per_partner_nums = (
                session.query(func.count(Agency.ebf_agency_id))
                .filter_by(ebf_agency_parent_id=agency.ebf_agency_id)
                .scalar()
            )
            per_user_nums = (
                session.query(func.count(User.ebf_user_id))
                .filter_by(ebf_user_agency_uid=agency_uid)
                .scalar()
            )
            total_benefit = (
                str(total_benefit.quantize(Decimal("0.00"))) if total_benefit else "0"
            )
            orders_id = (
                session.query(Benefit.order_id)
                .filter_by(agency_uid=agency_uid, is_valid=1)
                .filter(Benefit.status.in_([0, 1]))
                .filter(Benefit.create_time >= start_time)
                .filter(Benefit.create_time <= end_time)
                .distinct()
                .all()
            )
            total_fee = Decimal("0")
            for id_tuple in orders_id:
                id = id_tuple[0]
                order = session.query(Order).filter_by(sdef_order_id=id).first()
                if not order:
                    continue
                total_fee += order.sdef_order_fee + order.sdef_order_balance_fee
            total_fee = (
                str(total_fee.quantize(Decimal("0.00"))) if total_fee else "0.00"
            )
            agency_info = dict(
                total_fee=total_fee,  # 累计销售额
                total_benefit=total_benefit,  # 累计收益
                agency_id=agency.ebf_agency_id,
                name=agency.ebf_agency_name,
                phone=agency.ebf_agency_contact,
                parent_id=agency.ebf_agency_parent_id,
                invite_uid=agency.ebf_agency_invite_uid,
                career_uid=agency.ebf_agency_career_uid,
                type=type,
                per_partner_nums=per_partner_nums,  # 合伙人名下直属合伙人人数
                per_user_nums=per_user_nums,  # 合伙人名下直属普通用户人数
            )
            if user:
                agency_info["nickname"] = user.ebf_user_nickname
                agency_info["open_id"] = user.ebf_user_id
            context.append(agency_info)
        data = dict(
            partners=context,
            partner_nums=partner_nums,
        )
        session.close()
        return self.write(ret_msg(data=data))


class AccountBalance(ApiBaseHandler):
    async def get(self):
        open_id = await self.get_open_id()

        class AccountMoney(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_account_money", "model": AccountMoney},
            ]
        )
        am = session.query(AccountMoney).filter_by(ebf_am_user_id=open_id).first()
        if not am:
            account_balance = "0.00"
            cash = "0.00"
        else:
            account_balance = (
                str(am.ebf_am_money.quantize(Decimal("0.00"))) if am else "0.00"
            )
            if am.ebf_am_money >= 0 and am.ebf_am_cash >= 0:
                cash = am.ebf_am_cash
                if am.ebf_am_money < cash:
                    logger.error(f"可提现余额大于总余额: cash={cash} am_money={am.ebf_am_money}")
                    cash = am.ebf_am_money
                cash = str(cash.quantize(Decimal("0.00")))
            else:
                cash = "0.00"

        context = dict(account_balance=account_balance, cash=cash)
        session.close()
        return self.write(ret_msg(data=context))


class LastModified(ApiBaseHandler):
    """返回商品表最后修改时间戳，前端据此判断是否需要刷新展示内容"""

    async def get(self):
        class Goods(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_goods", "model": Goods},
            ]
        )
        filters = dict(sdef_goods_factory_uid=config.FACTORY_UID)
        new_goods = (
            session.query(Goods)
            .filter_by(**filters)
            .order_by(Goods.sdef_goods_update_time.desc())
            .all()[0]
        )
        new_date = new_goods.sdef_goods_update_time
        timestamp = time.mktime(new_date.timetuple())
        redis = redis_util.client
        last_time = redis.get("last_goods_timestamp")
        if not last_time or (
            last_time and float(last_time.decode("utf-8")) < timestamp
        ):
            redis.set("last_goods_timestamp", timestamp)
        context = dict(
            timestamp=timestamp,
        )
        session.close()
        return self.write(ret_msg(data=context))


class CartGoodsNums(ApiBaseHandler):
    async def get(self):
        open_id = await self.get_open_id()

        class Carts(object):
            pass

        class Goods(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_cart", "model": Carts},
                {"db_table": "sdet_goods", "model": Goods},
            ]
        )
        cart = session.query(Carts).filter_by(sdef_cart_device_id=open_id).first()
        cart_count = 0
        if cart:
            cart_goods = json.loads(cart.sdef_cart_goods)
            filter = dict(sdef_goods_status=1, sdef_goods_is_delete=0)
            for g in cart_goods:
                filter["sdef_goods_id"] = int(g["id"])
                _goods = (
                    session.query(Goods)
                    .filter(Goods.sdef_goods_count > 0)
                    .filter_by(**filter)
                    .first()
                )
                if not _goods:
                    continue
                cart_count = cart_count + g["count"]
        session.close()
        return self.write(ret_msg(data=cart_count))


class DeviceInfo(ApiBaseHandler):
    async def get(self):
        # sqlalchemy查询
        # class DeviceOwner(object):
        #     pass

        # session = self.get_session([
        #     {"db_table": "ebt_device_owner", "model": DeviceOwner},
        # ])
        # result = session.query(DeviceOwner).filter(DeviceOwner.ebf_device_id!=None,
        #                                            DeviceOwner.ebf_user_address!=None).all()
        # device_info = []
        # for d in result:
        #     device = dict(
        #         device_id=d.ebf_device_id,
        #         user_address=d.ebf_user_address
        #     )
        #     device_info.append(device)
        # context = dict(device_info=device_info)
        # return self.write(ret_msg(data=context))

        # sql语句查询
        device_info = []
        try:
            conn = connect(
                host=config.MYSQL_HOST,
                port=config.MYSQL_PORT,
                user=config.MYSQL_USER,
                passwd=config.MYSQL_PWD,
                database=config.MYSQL_DB,
                charset="utf8",
            )
            cs = conn.cursor()
            select_sql = "select ebf_device_id, ebf_user_address from ebt_device_owner"
            cs.execute(select_sql)
            result = cs.fetchall()
            cs.close()
        except Exception as e:
            logger.error(e)
        else:
            for d in result:
                if d[0] and d[1]:
                    device = dict(device_id=d[0], address=d[1])
                    device_info.append(device)
        finally:
            conn.close()
        context = dict(device_info=device_info)
        return self.write(ret_msg(data=context))


class DailyBenefitReturn(ApiBaseHandler):
    def get(self):
        order_id = self.get_parameter("order_id", None)

        class Order(object):
            pass

        class Benefit(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_order", "model": Order},
                {"db_table": "sdet_benefit", "model": Benefit},
            ]
        )
        o = session.query(Order).filter_by(sdef_order_id=order_id).first()
        agency_uid = o.sdef_order_agency_uid
        order_fee = o.sdef_order_fee
        pay_time = o.sdef_order_pay_time
        base_time = datetime.datetime(2018, 11, 24, 10, 0, 0)
        new_base_time = datetime.datetime(2018, 11, 27, 18, 30, 0)
        if pay_time > base_time:
            money = Decimal("5")
            if pay_time > new_base_time:
                count = order_fee / Decimal("2499")
            else:
                count = order_fee / Decimal("2500")
        else:
            money = Decimal("6")
            remainder = int(order_fee) % 1999
            if remainder:
                count = order_fee / Decimal("2300")
            else:
                count = order_fee / Decimal("1999")
        fee = money * count
        _filter = dict(order_id=order_id, agency_uid=agency_uid, fee=fee)
        benefit_times = (
            session.query(func.count(Benefit.id)).filter_by(**_filter).scalar()
        )
        benefits = session.query(Benefit).filter_by(**_filter).all()
        bf_list = []
        for b in benefits:
            bf_dict = dict(
                order_id=b.order_id,
                id=b.id,
                agency_uid=b.agency_uid,
                fee=str(b.fee),
                create_time=b.create_time.strftime("%Y年%m月%d日 %H:%M:%S"),
            )
            bf_list.append(bf_dict)
        pay_time = o.sdef_order_pay_time.strftime("%Y年%m月%d日 %H:%M:%S")
        context = dict(
            mysql_data=bf_list, pay_time=pay_time, benefit_times=benefit_times
        )
        session.close()
        return self.write(ret_msg(data=context))


class BenefitReturnTimes(ApiBaseHandler):
    async def get(self):
        class Order(object):
            pass

        class Benefit(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_order", "model": Order},
                {"db_table": "sdet_benefit", "model": Benefit},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user_agency", "model": UserAgency},
            ]
        )
        time_range = self.get_parameter("time_range", None)
        now = datetime.datetime.now()
        day_now = time.localtime()
        year = day_now.tm_year
        month = day_now.tm_mon
        day = day_now.tm_mday
        execute_date = datetime.datetime(2018, 7, 23, 0, 0, 0)  # 开始执行日期, 以实际为准
        if time_range:
            start_time, end_time = ApiHelper.get_time_range(time_range)
            date_end = start_time + datetime.timedelta(days=-1)
            date_end = date_end.replace(
                hour=23, minute=59, second=59, microsecond=999999
            )
        else:
            if now < datetime.datetime(year, month, day, 12, 30, 0):
                return self.write(ret_msg(code=-1, error_message="没到统计时间"))
            start_time = datetime.datetime(year, month, day, 0, 0, 0)
            end_time = datetime.datetime(year, month, day, 23, 59, 59)
            date_end = (now + datetime.timedelta(days=-1)).replace(
                hour=23, minute=59, second=59, microsecond=999999
            )
        logger.info(date_end)
        filters = dict(
            sdef_order_is_delete=0,
            sdef_order_pay_status=1,
            sdef_order_status=4,
            sdef_order_type=3,
            sdef_order_message=None,
        )
        orders = (
            session.query(Order)
            .filter_by(**filters)
            .filter(Order.sdef_order_pay_time >= execute_date)
            .filter(Order.sdef_order_pay_time <= date_end)
            .all()
        )

        err_order = []
        for o in orders:
            open_id = o.sdef_order_device_id
            order_id = o.sdef_order_id
            agency_uid = o.sdef_order_agency_uid
            order_fee = o.sdef_order_fee
            pay_time = o.sdef_order_pay_time
            base_time = datetime.datetime(2018, 11, 24, 10, 0, 0)
            new_base_time = datetime.datetime(2018, 11, 27, 18, 30, 0)
            user_agency = (
                session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()
            )
            agency = (
                session.query(Agency)
                .filter_by(ebf_agency_id=user_agency.ebf_agency_id)
                .first()
            )

            if agency_uid != agency.ebf_agency_uid:
                logger.error(
                    "订单没有绑定在自己名下: order_id=%s, open_id=%s, uid=%s"
                    % (order_id, open_id, agency_uid)
                )
                agency_uid = agency.ebf_agency_uid
                o.sdef_order_agency_uid = agency_uid

            if order_fee == Decimal("199") or order_fee == Decimal("980"):
                if not o.sdef_order_message:
                    o.sdef_order_message = "1"
                continue

            if o.sdef_order_describe == "underline":
                if not o.sdef_order_message:
                    o.sdef_order_message = "1"
                continue

            if pay_time > base_time:
                money = Decimal("5")
                if pay_time > new_base_time:
                    count = order_fee / Decimal("2499")
                else:
                    count = order_fee / Decimal("2500")
            else:
                money = Decimal("6")
                remainder = int(order_fee) % 1999
                if remainder:
                    count = order_fee / Decimal("2300")
                else:
                    count = order_fee / Decimal("1999")
            fee = money * count
            _filter = dict(order_id=order_id, agency_uid=agency_uid, fee=fee)
            benefit_times = (
                session.query(func.count(Benefit.id))
                .filter_by(**_filter)
                .filter(Benefit.create_time >= start_time)
                .filter(Benefit.create_time <= end_time)
                .scalar()
            )
            if benefit_times != 1:
                o_info = dict(
                    order_id=order_id,
                    open_id=open_id,
                    benefit_times=benefit_times,
                    fee=str(fee),
                    order_fee=str(order_fee),
                    pay_time=o.sdef_order_pay_time.strftime("%Y年%m月%d日 %H:%M:%S"),
                )
                err_order.append(o_info)
        context = dict(err_order=err_order)
        session.commit()
        session.close()
        return self.write(ret_msg(data=context))


class CrowdFundingOrder(ApiBaseHandler):
    async def get(self):
        class GoodsOrder(object):
            pass

        session = self.get_db_session([{"db_table": "sdet_order", "model": GoodsOrder}])
        time_range = self.get_parameter("time_range", None)
        now = datetime.datetime.now()
        page_index = int(self.get_parameter("page_index", 0))
        page_size = int(self.get_parameter("page_size", 10))
        ApiHelper.inspect_common_params(page_index, page_size)
        page_start = page_index * page_size
        if time_range:
            start_time, end_time = ApiHelper.get_time_range(time_range)
        else:
            start_time = datetime.datetime(2018, 7, 23, 0, 0, 0)
            end_time = now

        filters = dict(
            sdef_order_is_delete=0,
            sdef_order_pay_status=1,
            sdef_order_status=4,
            sdef_order_type=3,
        )
        orders = (
            session.query(GoodsOrder)
            .filter_by(**filters)
            .filter(GoodsOrder.sdef_order_pay_time >= start_time)
            .filter(GoodsOrder.sdef_order_pay_time <= end_time)
            .order_by(GoodsOrder.sdef_order_id.desc())[
                page_start : page_start + page_size
            ]
        )
        nums = (
            session.query(func.count(GoodsOrder.sdef_order_id))
            .filter_by(**filters)
            .filter(GoodsOrder.sdef_order_pay_time >= start_time)
            .filter(GoodsOrder.sdef_order_pay_time <= end_time)
            .scalar()
        )
        order_info = []
        for o in orders:
            message = None
            if o.sdef_order_message:
                message = o.sdef_order_message
            order = dict(
                order_id=o.sdef_order_id,
                device_id=o.sdef_order_device_id,
                order_fee=str(o.sdef_order_fee),
                order_type=o.sdef_order_type,
                order_name=o.sdef_order_name,
                order_describe=o.sdef_order_describe,
                pay_time=o.sdef_order_pay_time.strftime("%Y年%m月%d日 %H:%M:%S"),
                order_message=message,
            )
            order_info.append(order)
        context = dict(order_info=order_info, nums=nums)
        session.close()
        return self.write(ret_msg(data=context))


class RrecommenderBenefitDetail(ApiBaseHandler):
    async def get(self):
        class Benefit(object):
            pass

        session = self.get_db_session([{"db_table": "sdet_benefit", "model": Benefit}])
        order_id = self.get_parameter("order_id", None)
        if not order_id:
            return self.write(ret_msg(data=-1, error_message="缺少参数订单号！"))

        try:
            db = mongodb_util.db
            result = db.sdec_recommender.find_one({"order_id": order_id})
            if result:
                inviter_oid = result.get("inviter_oid", None)
                inviter_uid = UserHelper.get_agency_uid(inviter_oid)
                fee = int(result["fee"])
                pay_date = result["pay_time"]
                pay_time = pay_date.strftime("%Y-%m-%d %H:%M:%S")
                if not inviter_uid:
                    msg = "没有合伙人唯一标识！"
                    return self.write(ret_msg(data=-1, error_message=msg))
            else:
                msg = "查询数据为空"
                return self.write(ret_msg(data=-1, error_message=msg))
        except Exception as e:
            msg = "查询数据出错: e=%s" % e
            return self.write(ret_msg(data=-1, error_message=msg))

        base_time = datetime.datetime(2018, 11, 27, 18, 30, 0)
        if pay_date > base_time:
            count = fee / Decimal("2499")
        else:
            count = fee / Decimal("2500")
        _filter = dict(order_id=order_id, agency_uid=inviter_uid, fee=count, type=4)
        benefit_times = (
            session.query(func.count(Benefit.id)).filter_by(**_filter).scalar()
        )
        benefits = session.query(Benefit).filter_by(**_filter).all()
        bf_list = []
        for b in benefits:
            bf_dict = dict(
                order_id=b.order_id,
                id=b.id,
                agency_uid=b.agency_uid,
                fee=str(b.fee),
                create_time=b.create_time.strftime("%Y年%m月%d日 %H:%M:%S"),
            )
            bf_list.append(bf_dict)
        context = dict(
            benefit_list=bf_list, pay_time=pay_time, benefit_times=benefit_times
        )
        session.close()
        return self.write(ret_msg(data=context))


class ErrorBenefitOrder(ApiBaseHandler):
    async def get(self):
        class Benefit(object):
            pass

        session = self.get_db_session([{"db_table": "sdet_benefit", "model": Benefit}])
        time_range = self.get_parameter("time_range", None)
        now = datetime.datetime.now()
        day_now = time.localtime()
        year = day_now.tm_year
        month = day_now.tm_mon
        day = day_now.tm_mday
        if time_range:
            start_time, end_time = ApiHelper.get_time_range(time_range)
            date_end = start_time + datetime.timedelta(days=-1)
            date_end = date_end.replace(
                hour=23, minute=59, second=59, microsecond=999999
            )
        else:
            if now < datetime.datetime(year, month, day, 12, 30, 0):
                return self.write(ret_msg(code=-1, error_message="没到统计时间"))
            start_time = datetime.datetime(year, month, day, 0, 0, 0)
            end_time = datetime.datetime(year, month, day, 23, 59, 59)
            date_end = (now + datetime.timedelta(days=-1)).replace(
                hour=23, minute=59, second=59, microsecond=999999
            )
        try:
            db = mongodb_util.db
            result = db.sdec_recommender.find({"pay_time": {"$lte": date_end}}).sort(
                "pay_time", pymongo.DESCENDING
            )
        except Exception as e:
            msg = "查询数据出错: e=%s" % e
            return self.write(ret_msg(data=-1, error_message=msg))
        order_list = []
        err_order_list = []
        base_time = datetime.datetime(2018, 11, 27, 18, 30, 0)
        for o in result:
            order_id = o["order_id"]
            inviter_oid = o.get("inviter_oid", None)
            pay_date = o["pay_time"]
            pay_time = pay_date.strftime("%Y年%m月%d日 %H:%M:%S")
            fee = int(o["fee"])
            inviter_uid = UserHelper.get_agency_uid(inviter_oid)
            o_info = dict(
                order_id=order_id, inviter_oid=inviter_oid, pay_time=pay_time, fee=fee
            )
            order_list.append(o_info)
            if pay_date > base_time:
                count = fee / Decimal("2499")
            else:
                count = fee / Decimal("2500")
            _filter = dict(order_id=order_id, agency_uid=inviter_uid, fee=count, type=4)
            benefit_times = (
                session.query(func.count(Benefit.id))
                .filter_by(**_filter)
                .filter(Benefit.create_time >= start_time)
                .filter(Benefit.create_time <= end_time)
                .scalar()
            )
            if benefit_times != 1:
                err_order_list.append(order_id)
        context = dict(order_list=order_list, err_order_list=err_order_list)
        session.close()
        return self.write(ret_msg(data=context))


class ScanUserNumber(ApiBaseHandler):
    async def get(self):
        recommend_user = self.get_parameter("recommend_user", None)
        time_range = self.get_parameter("time_range", None)
        uid = self.get_parameter("uid", None)

        db = mongodb_util.db
        user_info = []
        if time_range:
            logger.info("time_range=%s" % time_range)
            start_time, end_time = ApiHelper.get_time_range(time_range)
        else:
            start_time = datetime.datetime(2018, 7, 20, 0, 0, 0)
            end_time = datetime.datetime.now()

        if not (recommend_user or uid):
            result = db.scan_user_number_info.find(
                {"create_date": {"$gte": start_time, "$lte": end_time}}
            )

        if recommend_user:
            result = db.scan_user_number_info.find(
                {
                    "create_date": {"$gte": start_time, "$lte": end_time},
                    "recommend_user": recommend_user,
                }
            )
        elif uid:
            result = db.scan_user_number_info.find(
                {"create_date": {"$gte": start_time, "$lte": end_time}, "uid": uid}
            )
        result = result.sort("create_date", pymongo.ASCENDING)
        for u in result:
            create_time = u["create_date"]
            user = dict(
                open_id=u["open_id"],
                recommend_user=u["recommend_user"],
                number=u["number"],
                nickname=u["nickname"],
                uid=u.get("uid", None),
                end_num=u["end_num"],
                create_date=create_time.strftime("%Y年%m月%d日 %H:%M:%S"),
            )
            user_info.append(user)
        count = result.count()
        context = dict(count=count, user_info=user_info)
        return self.write(ret_msg(data=context))


class IsSubscribe(ApiBaseHandler):
    async def get(self):
        open_id = await self.get_open_id()
        result = await self.get_user_info(open_id)
        if "subscribe" not in result:
            logger.error(f"IsSubscribe: 判断用户是否关注出错！ open_id={open_id} res={result}")
            return self.write(ret_msg(code=-1, data=result))
        return self.write(ret_msg(data=result))


class UpdateUserInfo(ApiBaseHandler):
    async def get(self):
        class User(object):
            pass

        session = self.get_db_session([{"db_table": "ebt_user", "model": User}])
        open_id = await self.get_open_id()
        result = await self.get_user_info(open_id)
        subscribe = result.get("subscribe", None)

        if "subscribe" not in result:
            logger.error(f"判断用户是否关注出错！ open_id={open_id} res={result}")
            return self.write(ret_msg(code=-1, data=result))

        if subscribe == 0:
            return self.write(ret_msg(-1, error_message="未关注公众号"))
        elif subscribe == 1:
            user = session.query(User).filter_by(ebf_user_id=open_id).first()
            if not user:
                return self.write(ret_msg(-1, error_message="没有注册账号"))
            headurl = result.get("headimgurl")
            user.ebf_user_headurl = headurl
            nickname = replace_emoji(result.get("nickname", "未关注"))
            if len(nickname) > 32:
                user.ebf_user_nickname = nickname[0:32]
            else:
                user.ebf_user_nickname = nickname
            user.ebf_user_gender = result.get("sex", 0)
            session.commit()
            session.close()
        return self.write(ret_msg(data=headurl))


class LoginDate(ApiBaseHandler):
    async def get(self):
        class Agency(object):
            pass

        class User(object):
            pass

        class UserAgency(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_user_agency", "model": UserAgency},
            ]
        )
        open_id = await self.get_open_id()
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        user_agency = (
            session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()
        )

        if not user:
            return self.write(ret_msg(code=-1, error_message="用户不存在！"))

        if not user_agency:
            return self.write(ret_msg(code=-1, error_message="用户不是合伙人！"))

        now = datetime.datetime.now()
        last_date = user.ebf_user_login_date
        # flag = True表示弹框相隔时间已经有五天， False表示弹框相隔时间还没有五天
        if last_date:
            days = (now - last_date).days
            if days >= 5:
                flag = True
                user.ebf_user_login_date = now
            else:
                flag = False
        else:
            flag = True
            user.ebf_user_login_date = now
        session.commit()
        session.close()
        return self.write(ret_msg(data=flag))


class BenefitRanking(ApiBaseHandler):
    async def get(self):
        class User(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        class Benefit(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user_agency", "model": UserAgency},
                {"db_table": "sdet_benefit", "model": Benefit},
            ]
        )
        # month=0表示查询当月， month=-1表示查询上个月
        m = self.get_parameter("month", None)
        default_headurl = f"https://{DOMAIN}/static/img/content/logo-60x60.png"

        if not m:
            return self.write(ret_msg(data=-1, error_message="缺少请求参数！"))

        query_month = int(m)
        today = datetime.date.today()

        if query_month == 0:
            year = today.year
            month = today.month
            date = today.strftime("%Y-%m")
        elif query_month == -1:
            first = today.replace(day=1)  # 获取当月第一天
            last_month = first - datetime.timedelta(days=1)  # 获取上个月最后一天
            year = last_month.year
            month = last_month.month
            date = last_month.strftime("%Y-%m")
        else:
            return self.write(ret_msg(data=-1, error_message="请求参数错误！"))

        open_id = await self.get_open_id()
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            return self.write(ret_msg(data=-1, error_message="没有用户信息！"))

        user_agency = (
            session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()
        )
        if not user_agency:
            return self.write(ret_msg(data=-1, error_message="没有酒庄代表身份记录！"))

        ag = (
            session.query(Agency)
            .filter_by(ebf_agency_id=user_agency.ebf_agency_id)
            .first()
        )
        if not ag:
            return self.write(ret_msg(data=-1, error_message="无酒庄代表身份记录！"))

        uid = ag.ebf_agency_uid
        total_benefit = (
            session.query(func.sum(Benefit.fee))
            .filter_by(agency_uid=uid, is_valid=1)
            .filter(or_(Benefit.status == 0, Benefit.status == 1))
            .filter(
                and_(
                    extract("year", Benefit.create_time) == year,
                    extract("month", Benefit.create_time) == month,
                )
            )
            .scalar()
        )
        own_info = dict(
            total_fee="%.2f" % total_benefit if total_benefit else "0.00",
            headurl=user.ebf_user_headurl if user.ebf_user_headurl else default_headurl,
            nickname=user.ebf_user_nickname,
        )
        flag = False
        item = session.query(Agency.ebf_agency_uid).subquery()
        result = (
            session.query(Benefit.agency_uid.label("uid"), func.sum(Benefit.fee))
            .filter_by(is_valid=1)
            .filter(or_(Benefit.status == 0, Benefit.status == 1))
            .filter(
                and_(
                    extract("year", Benefit.create_time) == year,
                    extract("month", Benefit.create_time) == month,
                )
            )
            .join(item, Benefit.agency_uid == item.c.ebf_agency_uid)
            .group_by("uid")
            .order_by(func.sum(Benefit.fee).desc())[0:10]
        )

        context = []
        for agency_uid, fee in result:
            agency = session.query(Agency).filter_by(ebf_agency_uid=agency_uid).first()
            if not agency:
                continue

            if uid == agency_uid and not flag:
                flag = True

            agency_id = agency.ebf_agency_id
            ua = session.query(UserAgency).filter_by(ebf_agency_id=agency_id).first()
            if not ua:
                continue

            oid = ua.ebf_ua_bind_user_id
            if not oid:
                continue

            u = session.query(User).filter_by(ebf_user_id=oid).first()
            if not u:
                continue

            total_fee = "%.2f" % fee if fee else "0.00"
            name = agency.ebf_agency_name
            agency_type = agency.ebf_agency_type

            if agency_type == 2:
                type = "资深酒庄代表"
            elif agency_type == 1:
                type = "高级酒庄代表"
            elif agency_type == 0:
                type = "初级酒庄代表"
            else:
                type = "不合法类型"

            agency_id = agency.ebf_agency_id
            agency_info = dict(
                total_fee=total_fee,
                name=name,
                agency_uid=agency_uid,
                type=type,
                agency_type=agency_type,
                agency_id=agency_id,
                headurl=u.ebf_user_headurl if u.ebf_user_headurl else default_headurl,
                nickname=u.ebf_user_nickname,
            )
            context.append(agency_info)

        own_info["flag"] = flag
        data = dict(own_info=own_info, context=context)
        session.close()
        return self.write(ret_msg(data=data, error_message=date))


class UploadPoster(ApiBaseHandler):
    async def post(self):
        open_id = await self.get_open_id()
        auth_result = self.power_auth(open_id)
        if not auth_result:
            return self.write(ret_msg(code=-1, error_message="没有上传图片权限，请联系管理员！"))

        img_list = self.request.files.get("img", None)
        size = int(self.request.headers.get("Content-Length")) / 1024
        logger.info("size=%s" % size)

        if size > 2000:
            return self.write(ret_msg(code=-1, error_message="上传文件不能大于2M！"))

        if not img_list:
            return self.write(ret_msg(code=-1, error_message="请选择要上传的图片！"))

        img = img_list[0]
        secret_id = config.COS_APP_SECRET_ID
        secret_key = config.COS_APP_SECRET_KEY
        region = "ap-guangzhou"
        token = ""
        scheme = "https"

        try:
            cfg = CosConfig(
                Region=region,
                Secret_id=secret_id,
                Secret_key=secret_key,
                Token=token,
                Scheme=scheme,
            )
            client = CosS3Client(cfg)
            base_url = (
                "https://" + "style-1251902022." + "file.myqcloud.com/static/img/"
            )
            filename = generator_trade_no() + "_" + img["filename"]
            response = client.put_object(
                Bucket=config.COS_BUCKET + "-" + config.COS_APP_ID,
                Body=img["body"],
                Key="static/img/" + filename,
            )
        except Exception as e:
            logger.error("图片上传失败： %s" % e)
            return self.write(ret_msg(code=-1, error_message="图片上传失败！"))

        logger.debug(response)
        img_url = base_url + filename
        return self.write(ret_msg(data=img_url))


class SavePosterInfo(ApiBaseHandler):
    async def get(self):
        open_id = await self.get_open_id()
        auth_result = self.power_auth(open_id)
        if not auth_result:
            return self.write(ret_msg(code=-1, error_message="没有查看海报权限，请联系管理员！"))

        try:
            db = mongodb_util.db
            result = db.sdec_poster_info.find().sort("_id", pymongo.DESCENDING)
        except Exception as e:
            logger.error("获取海报列表信息失败: %s" % e)
            return self.write(ret_msg(code=-1, error_message="获取海报列表信息失败！"))

        count = result.count()
        poster_list = []
        for poster in result:
            poster["create_date"] = poster["create_date"].strftime("%Y-%m-%d %H:%M:%S")
            url = poster["img_url"]

            if ".png" in url or ".PNG" in url:
                pre = "data:image/png;base64,"
            elif ".jpg" in url or ".JPG" in url:
                pre = "data:image/jpg;base64,"
            else:
                pre = None

            response = requests.get(url)
            base64_img = base64.b64encode(response.content).decode()
            poster["base64_img"] = pre + base64_img
            poster_list.append(poster)

        return self.write(ret_msg(data=poster_list, error_message=count))

    async def post(self):
        open_id = await self.get_open_id()
        auth_result = self.power_auth(open_id)
        if not auth_result:
            return self.write(ret_msg(code=-1, error_message="没有上传海报权限，请联系管理员！"))

        # 请求参数
        img_url = self.get_parameter("img_url", None)  # 背景图片地址
        x = float(self.get_parameter("x", 0))  # 二维码距离背景图片左边距离，单位像素
        y = float(self.get_parameter("y", 0))  # 二维码距离背景图片顶部距离，单位像素
        poster_title = self.get_parameter("poster_title", None)
        qrcode_content = self.get_parameter("qrcode_content", None)
        share_title = self.get_parameter("share_title", None)
        share_content = self.get_parameter("share_content", None)
        url = self.get_parameter("url", None)

        if not all([img_url, x, y, poster_title, qrcode_content, url]):
            return self.write(ret_msg(code=-1, error_message="缺少请求参数或请求参数错误！"))

        data = dict(
            _id=generator_trade_no(),
            img_url=img_url,
            x=x,
            y=y,
            poster_title=poster_title,
            qrcode_content=qrcode_content,
            share_title=share_title,
            share_content=share_content,
            create_date=datetime.datetime.now(),
            url=url,
        )

        try:
            db = mongodb_util.db
            db.sdec_poster_info.insert(data)
        except Exception as e:
            logger.error("海报上传失败: %s" % e)
            return self.write(ret_msg(code=-1, error_message="海报上传失败！"))

        return self.write(ret_msg())


class DelPoster(ApiBaseHandler):
    async def post(self):
        id = self.get_parameter("id", None)
        if not id:
            return self.write(ret_msg(code=-1, error_message="请输入要删除的海报编号！"))

        open_id = await self.get_open_id()
        auth_result = self.power_auth(open_id)
        if not auth_result:
            return self.write(ret_msg(code=-1, error_message="没有删除海报权限，请联系管理员！"))

        try:
            db = mongodb_util.db
            result = db.sdec_poster_info.delete_one({"_id": id})
            if not result.deleted_count:
                return self.write(ret_msg(code=-1, error_message="海报编号不存在!"))
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="删除海报失败!"))

        return self.write(ret_msg())


class GetCoupon(ApiBaseHandler):
    def is_allow(self, order_id, open_id):
        if not order_id:
            return False, "缺少请求参数！"

        class Order(object):
            pass

        class CouponUser(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_order", "model": Order},
                {"db_table": "ebt_coupon_user", "model": CouponUser},
            ]
        )

        filters = dict(
            sdef_order_id=order_id,
            sdef_order_device_id=open_id,
            sdef_order_type=1,
            sdef_order_pay_status=1,
            sdef_order_is_delete=0,
        )
        filters2 = dict(user_id=open_id, coupon_id=2, order_id=order_id)
        order = session.query(Order).filter_by(**filters).first()
        cu1 = session.query(CouponUser).filter_by(**filters2).first()
        if not order:
            session.close()
            return False, "订单号错误"

        if cu1:
            session.close()
            return False, "已领取餐券，不能重复领取"

        session.close()
        return True, "1"

    async def get(self):
        order_id = self.get_parameter("order_id", None)
        open_id = await self.get_open_id()
        result, msg = self.is_allow(order_id, open_id)
        if result:
            return self.write(ret_msg())
        else:
            return self.write(ret_msg(code=-1, error_message=msg))

    async def post(self):
        order_id = self.get_parameter("order_id", None)
        action = self.get_parameter("action", None)
        open_id = await self.get_open_id()
        result, msg = self.is_allow(order_id, open_id)
        if not result:
            return self.write(ret_msg(code=-1, error_message=msg))

        class Order(object):
            pass

        class CouponUser(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_order", "model": Order},
                {"db_table": "ebt_coupon_user", "model": CouponUser},
            ]
        )

        filters = dict(
            sdef_order_id=order_id,
            sdef_order_device_id=open_id,
            sdef_order_type=1,
            sdef_order_pay_status=1,
            sdef_order_is_delete=0,
        )
        order = session.query(Order).filter_by(**filters).first()
        money = (order.sdef_order_fee + order.sdef_order_balance_fee) * Decimal("0.2")
        if action == "receive":
            now = datetime.datetime.now()
            cu = CouponUser()
            cu.user_id = open_id
            cu.coupon_id = 2
            cu.order_id = order_id
            cu.coupon_money = int(money)
            cu.create_time = now
            cu.status = 0
            cu.is_active = 0
            session.add(cu)
            session.commit()
            logger.info(f"create_time={now}, order_id={order_id}")

        session.close()
        return self.write(ret_msg())


class UseCoupon(ApiBaseHandler):
    async def post(self):
        store_id = int(self.get_parameter("store_id", 0))
        room_id = self.get_parameter("room_id", None)
        id = int(self.get_parameter("id", 0))  # 餐券编号
        open_id = await self.get_open_id()
        if not id:
            return self.write(ret_msg(code=-1, error_message="缺少参数餐券编号"))

        if not store_id:
            return self.write(ret_msg(code=-1, error_message="缺少参数门店编号"))

        if not room_id:
            return self.write(ret_msg(code=-1, error_message="缺少参数序号"))

        class Order(object):
            pass

        class Benefit(object):
            pass

        class CouponUser(object):
            pass

        class CouponOrder(object):
            pass

        class Agency(object):
            pass

        class Goods(object):
            pass

        class User(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_order", "model": Order},
                {"db_table": "sdet_benefit", "model": Benefit},
                {"db_table": "ebt_coupon_user", "model": CouponUser},
                {"db_table": "ebt_coupon_order", "model": CouponOrder},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "ebt_user", "model": User},
            ]
        )

        filters = dict(id=id, user_id=open_id, coupon_id=2, status=0, is_active=1)
        cu = session.query(CouponUser).filter_by(**filters).first()
        now = datetime.datetime.now()
        order_id = generator_trade_no()
        agency = session.query(Agency).filter_by(ebf_agency_id=store_id).first()
        if not agency:
            session.close()
            return self.write(ret_msg(code=-1, error_message="门店不存在"))

        if not cu:
            session.close()
            return self.write(ret_msg(code=-1, error_message="餐券不存在"))

        uid = agency.ebf_agency_uid
        money = cu.coupon_money
        cart_goods = list()
        goods_id = promotion.STORE_COUPON_GOODS_ID  # 餐券核销商品
        goods = session.query(Goods).filter_by(sdef_goods_id=goods_id).first()
        goods_dict = dict(
            id=goods_id,
            count=1,
            goods_img=json.loads(goods.sdef_goods_thumbnail)[0],
            goods_name=goods.sdef_goods_name,
            goods_price=money,
            goods_member_price=money,
            goods_pin_price=money,
            balance_rate=0,
            rate=0,
            master_rate=0,
            invite_rate=0,
            invite_invite_rate=0,
            career_rate=0,
            invite_career_rate=0,
            supplier=0,
            goods_cost=0,
        )
        cart_goods.append(goods_dict)
        try:
            cu.status = 1

            co = CouponOrder()
            co.user_id = open_id
            co.store_id = store_id
            co.coupon_user_id = id
            co.order_id = order_id
            co.order_total = money
            co.money = money
            co.actual_paid = 0
            co.paid_balance = 0
            co.create_time = now
            co.status = 1
            session.add(co)

            benefit = Benefit()
            benefit.order_id = order_id
            benefit.factory_uid = FACTORY_UID
            benefit.agency_uid = uid
            benefit.type = 2
            benefit.fee = money
            benefit.order_fee = money
            benefit.rate = 1
            benefit.status = 1
            benefit.is_valid = 1
            benefit.is_finish = 1
            benefit.remarks = "门店无门槛抵扣券"
            benefit.update_time = now
            benefit.create_time = now
            session.add(benefit)

            order = Order()
            order.sdef_order_id = order_id
            order.sdef_order_factory_uid = FACTORY_UID
            order.sdef_order_device_id = open_id
            order.sdef_order_fee = money
            order.sdef_order_goods = json.dumps(cart_goods, cls=JSONEncoder)
            order.sdef_order_balance_fee = 0
            order.sdef_order_name = "餐券抵扣订单"
            order.sdef_order_status = 4
            order.sdef_order_pay_status = 1
            order.sdef_order_pay_time = now
            order.sdef_order_type = 5  # 5=餐券抵扣订单
            order.sdef_order_ip = self.request.remote_ip
            order.sdef_order_create_time = now
            order.sdef_order_delivery_fee = 0
            order.sdef_order_agency_uid = uid
            order.sdef_order_store_id = store_id
            order.sdef_order_room_id = room_id
            order.sdef_order_ship_type = 1
            order.sdef_order_remarks = "所用餐券编号：" + str(id)
            order.sdef_order_coupon_fee = 0
            session.add(order)
            session.commit()
        except Exception as e:
            logger.error(e)
            session.rollback()
            session.close()
            return self.write(ret_msg(code=-1, error_message="餐券核销失败，请稍后重试"))

        # 发送餐券核销收益模版消息
        agency_id = agency.ebf_agency_id
        agency_type = agency.ebf_agency_type
        agency_openid = UserHelper.get_agency_openid(agency_id)
        if agency_openid:
            user = session.query(User).filter_by(ebf_user_id=open_id).first()
            name = user.ebf_user_nickname if user else None
            if name == "未关注" or name is None:
                name = ""
            first = f"您好！您有新的餐券核销收益到账: {name} 【序号: {room_id}】"
            tasks.send_order_benefit_notice.delay(
                first,
                order_id,
                str(benefit.order_fee.quantize(Decimal("0.00"))),
                str(benefit.fee.quantize(Decimal("0.00"))),
                agency_openid,
                agency_type,
            )
        # 给店家及所有店员发送核销订单通知
        oid_list = await self.get_clerk_oid(store_id)
        first = "有新的餐券核销订单，点击“详情”进入订单列表查看！"
        value = "请确认餐券金额，序号无误后才能予以核销！【餐券金额：%s，序号：%s】！" % (str(money), room_id)
        tasks.send_new_order_notice0.delay(
            oid_list, room_id, store_id, order_id, first, value
        )
        session.close()
        return self.write(ret_msg())

    async def get_clerk_oid(self, store_id):
        class User(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user_agency", "model": UserAgency},
            ]
        )

        oid_list = list()
        agencys = (
            session.query(Agency)
            .filter_by(ebf_agency_parent_id=store_id, ebf_agency_type=4)
            .order_by(Agency.ebf_agency_id.desc())
            .all()
        )
        for g in agencys:
            id = g.ebf_agency_id
            ua = session.query(UserAgency).filter_by(ebf_agency_id=id).first()
            if ua and ua.ebf_ua_bind_user_id:
                oid_list.append(ua.ebf_ua_bind_user_id)

        ua2 = session.query(UserAgency).filter_by(ebf_agency_id=store_id).first()
        if ua2 and ua2.ebf_ua_bind_user_id:
            oid_list.append(ua2.ebf_ua_bind_user_id)
        session.close()
        return oid_list


class GetRedPacket(ApiBaseHandler):
    async def post(self):
        class GoodsOrder:
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_order", "model": GoodsOrder},
            ]
        )

        await self.get_open_id()
        order_id = self.get_parameter("order_id", None)
        if not order_id:
            session.close()
            return self.write(ret_msg(code=-1, error_message="缺少参数订单编号"))

        pay = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
        if not pay:
            logger.error(f"订单不存在 {order_id}")
            session.close()
            return self.write(ret_msg(code=-1, error_message="订单编号错误"))

        if pay.sdef_order_type != OrderType.FREE_CARD:
            session.close()
            return self.write(ret_msg(code=-1, error_message="订单类型错误"))

        if pay.sdef_order_pay_status != PayStatus.SUCCESS:
            logger.error(f"非已支付订单 {order_id}")
            session.close()
            return self.write(ret_msg(code=-1, error_message="订单未支付"))

        if pay.sdef_order_fee < Decimal("1"):
            session.close()
            return self.write(ret_msg(code=-1, error_message="订单金额小于1元"))

        result = get_red_packet(order_id)
        if result:
            money = "%0.2f" % result
            session.close()
            return self.write(ret_msg(data=money))
        else:
            session.close()
            return self.write(ret_msg(code=-1, error_message="红包领取失败"))


class UpdateInfo(ApiBaseHandler):
    async def post(self):
        open_id = await self.get_open_id()
        phone = self.get_parameter("phone", None)
        name = self.get_parameter("name", None)
        address = self.get_parameter("address", None)
        lat = self.get_parameter("lat", None)
        lng = self.get_parameter("lng", None)

        if not re.match(r"^1\d{10}$", phone):
            return self.write(ret_msg(code=-1, error_message="手机号格式不正确"))

        if not name:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数商家名称"))

        if not address:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数商家地址"))

        if not lat or not lng:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数经纬度"))

        class User(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user_agency", "model": UserAgency},
            ]
        )

        ua = session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()
        if not ua:
            session.close()
            logger.error(f"发卡商户注册: 请先扫码绑定微信 open_id={open_id} ")
            return self.write(ret_msg(code=-1, error_message="请先扫码绑定微信"))

        agency_id = ua.ebf_agency_id
        agency = session.query(Agency).filter_by(ebf_agency_id=agency_id).first()
        if agency.ebf_agency_type != 5 or agency.ebf_agency_sub_type != 3:
            session.close()
            logger.error(f"发卡商户注册: 非普通用户无法注册商户 open_id={open_id} agency_id={agency_id}")
            return self.write(ret_msg(code=-1, error_message="非普通用户无法注册商户"))

        if agency.ebf_agency_longitude and agency.ebf_agency_latitude:
            session.close()
            logger.error(
                f"发卡商户注册: 已经是商户身份无需重复注册 open_id={open_id} agency_id={agency_id}"
            )
            return self.write(ret_msg(code=-1, error_message="已经是商户身份无需重复注册"))

        agency.ebf_agency_contact = phone
        agency.ebf_agency_address = address
        agency.ebf_agency_name = name
        agency.ebf_agency_latitude = lat
        agency.ebf_agency_longitude = lng
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if user.ebf_user_agency_uid != agency.ebf_agency_uid:
            user.ebf_user_agency_uid = agency.ebf_agency_uid

        session.commit()
        session.close()
        logger.info(f"发卡商户注册: 成功 open_id={open_id} agency_id={agency_id}")
        return self.write(ret_msg())


class ExpertRegister(ApiBaseHandler):
    def update_user_uid(self, open_id, agency_uid):
        try:

            class User(object):
                pass

            session = self.get_db_session([{"db_table": "ebt_user", "model": User}])

            user = session.query(User).filter_by(ebf_user_id=open_id).first()
            user.ebf_user_agency_uid = agency_uid
            session.commit()
            session.close()
        except Exception as e:
            session.close()
            logger.error("用户注册修改uid失败：%s" % e)

    async def add_agency(
        self,
        type,
        open_id,
        inviter_oid,
        name,
        store_name,
        profile,
        address,
        phone,
        lat,
        lng,
        real_shop_id=None,
    ):
        class User(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user_agency", "model": UserAgency},
            ]
        )

        ua = session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()
        if ua:
            session.close()
            return self.write(ret_msg(code=-1, error_message="已经注册成功，不能重复注册"))

        redis = redis_util.client
        result = redis.get(f"register_{open_id}")
        if result:
            session.close()
            return self.write(ret_msg(code=-1, error_message="不能重复请求"))
        else:
            redis.setex(f"register_{open_id}", 60, 1)

        flag = False
        password = "style999"
        md5_obj = md5()
        md5_obj.update(password.encode("utf-8"))
        pwd = md5_obj.hexdigest()
        logo_url = f"https://{DOMAIN}/static/img/content/logo-60x60.png"
        agency_uid = str(uuid.uuid1())
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        invite_user = session.query(User).filter_by(ebf_user_id=inviter_oid).first()
        if not invite_user:
            logger.error(f"邀请人不存在: oid={open_id} inviter_oid={inviter_oid}")
            session.close()
            return self.write(ret_msg(code=-1, error_message="邀请人不存在"))

        uid = invite_user.ebf_user_agency_uid
        if not user:
            logger.info("创建用户：open_id=%s" % open_id)
            flag = True
            await self.create_user(open_id, uid, inviter_oid)
            user = session.query(User).filter_by(ebf_user_id=open_id).first()

        if (
            user.ebf_user_agency_uid == config.DEFAULT_AGENCY_UID
            and uid != config.DEFAULT_AGENCY_UID
        ):
            parent_uid = uid
        else:
            parent_uid = user.ebf_user_agency_uid

        work_time = {
            "day": [1, 2, 3, 4, 5, 6, 7],
            "am": "00:00-14:00",
            "pm": "14:00-24:00",
        }
        work_time = json.dumps(work_time)
        parent_agency = (
            session.query(Agency).filter_by(ebf_agency_uid=parent_uid).first()
        )
        parent_agency_id = (
            parent_agency.ebf_agency_id if parent_agency else config.DEFAULT_AGENCY_ID
        )
        depth = parent_agency.ebf_agency_depth + 1 if parent_agency else 2
        career_agency = UserHelper.get_career_agency(parent_uid)
        career_agency_uid = (
            career_agency.ebf_agency_uid if career_agency else config.DEFAULT_AGENCY_UID
        )
        logger.info(
            f"add_agency: parent_uid={parent_uid}, open_id={open_id}, inviter_oid={inviter_oid}"
        )

        try:
            _agency = Agency()
            _agency.ebf_agency_name = store_name
            _agency.ebf_agency_real_name = name
            _agency.ebf_agency_uid = agency_uid
            _agency.ebf_agency_contact = phone
            _agency.ebf_factory_id = config.FACTORY_ID
            _agency.ebf_agency_parent_id = parent_agency_id
            _agency.ebf_agency_career_uid = career_agency_uid
            _agency.ebf_agency_invite_uid = uid
            _agency.ebf_agency_depth = depth
            _agency.ebf_agency_create_time = datetime.datetime.now()
            _agency.ebf_agency_address = address
            _agency.ebf_agency_latitude = lat
            _agency.ebf_agency_longitude = lng
            _agency.ebf_agency_work_time = work_time
            _agency.ebf_agency_profile = profile

            if real_shop_id:
                _agency.ebf_investor_id = real_shop_id

            if type == 1:
                # 商家
                _agency.ebf_agency_type = 3
                _agency.ebf_agency_sub_type = 1
            elif type == 2:
                # 行家
                _agency.ebf_agency_type = 3
                _agency.ebf_agency_sub_type = 2
            else:
                # 新事业合伙人，付款后改变类型为(3, 3)
                _agency.ebf_agency_type = 0
                _agency.ebf_agency_sub_type = 0

            if _agency.ebf_agency_sub_type == 3:
                _agency.ebf_agency_is_active = 1  # 1=门店默认开通，0=需人工审核后开通
            else:
                _agency.ebf_agency_is_active = 1  # 1=门店默认开通，0=需人工审核后开通

            session.add(_agency)
            session.flush()
            agency_id = _agency.ebf_agency_id
            id_str = str(agency_id)
            # 增加合伙人后台用户记录
            new_user = User()
            new_user.ebf_user_id = "P" + id_str
            new_user.ebf_user_password = pwd
            new_user.user_create_date = datetime.datetime.utcnow()
            new_user.ebf_user_phone = phone
            new_user.ebf_user_nickname = user.ebf_user_nickname
            new_user.ebf_user_factory_id = config.FACTORY_ID
            new_user.ebf_user_type = 3
            new_user.ebf_user_gender = user.ebf_user_gender
            new_user.ebf_user_agency_uid = agency_uid
            new_user.ebf_user_headurl = logo_url
            session.add(new_user)
            session.flush()
            # 增加user_agency记录
            _user_agency = UserAgency()
            _user_agency.ebf_user_id = "P" + id_str
            _user_agency.ebf_agency_id = agency_id
            _user_agency.ebf_ua_bind_user_id = open_id
            session.add(_user_agency)
            # 更新用户信息
            user.ebf_user_agency_uid = agency_uid
            user.ebf_user_phone = phone
            user.ebf_user_recommend_user = inviter_oid
        except Exception as e:
            logger.error(e)
            session.rollback()
            session.close()
            return self.write(ret_msg(code=-1, error_message="注册失败,请重试"))

        session.commit()
        session.close()
        if flag:
            self.update_user_uid(open_id, agency_uid)
        # 触发注册事件
        tasks.store_registered.delay(agency_id)
        return self.write(ret_msg())

    async def post(self):
        phone = self.get_parameter("phone", None)
        store_name = self.get_parameter("store_name", None)
        name = self.get_parameter("name", None)
        inviter_oid = self.get_parameter("inviter_oid", None)
        address = self.get_parameter("address", None)
        shop_type = int(self.get_parameter("type", 1))  # 1=商家 2=行家 3=新事业合伙人
        profile = self.get_parameter("profile", None)
        lat = self.get_parameter("lat", None)
        lng = self.get_parameter("lng", None)

        real_shop_id = self.get_parameter("real_shop_id", None)  # 挂靠运营中心实体店（3.3)

        open_id = await self.get_open_id()
        logger.info(f"register: inviter_oid={inviter_oid}, open_id={open_id}")

        if not re.match(r"^1\d{10}$", phone):
            return self.write(ret_msg(code=-1, error_message="手机号格式不正确"))

        if not open_id:
            return self.write(ret_msg(code=-1, error_message="系统繁忙，请稍后重试！"))

        if shop_type not in [1, 2, 3]:
            return self.write(ret_msg(code=-1, error_message="请求参数类型错误！"))

        class User(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user_agency", "model": UserAgency},
            ]
        )

        logo_url = f"https://{DOMAIN}/static/img/content/logo-60x60.png"
        work_time = {
            "day": [1, 2, 3, 4, 5, 6, 7],
            "am": "00:00-14:00",
            "pm": "14:00-24:00",
        }
        work_time = json.dumps(work_time)

        if not inviter_oid:
            user = session.query(User).filter_by(ebf_user_id=open_id).first()
            inviter_oid = user.ebf_user_recommend_user

        if real_shop_id:
            # 如果虚拟店挂靠运营中心（实体店）
            shop = session.query(Agency).filter_by(ebf_agency_id=real_shop_id).first()
            if not shop:
                logger.error(f"门店注册：运营中心实体店{real_shop_id}不存在！")
                return self.write(ret_msg(-1, error_message="挂靠运营中心实体店不存在"))
            # 从运营中心实体店获取相关信息
            store_name = shop.ebf_agency_name
            address = shop.ebf_agency_address
            lat = shop.ebf_agency_latitude
            lng = shop.ebf_agency_longitude
            work_time = shop.ebf_agency_work_time

        ua = session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()
        if ua:
            # 如果已经是合伙人，升级账户
            if shop_type == 1:
                content = "商家"
            elif shop_type == 2:
                content = "行家"
            else:
                content = "新事业部"
            agency_id = ua.ebf_agency_id
            agency = session.query(Agency).filter_by(ebf_agency_id=agency_id).first()
            agency_type = agency.ebf_agency_type
            sub_type = agency.ebf_agency_sub_type
            if agency_type == 3 and sub_type == shop_type:
                msg = f"已成为{content}，无需重复注册！"
                session.close()
                return self.write(ret_msg(code=-1, error_message=msg))
            elif agency_type == 3 and sub_type:
                msg = f"非普通用户不能注册{content}！有疑问请在微信公众号留言或拨打客服电话人工处理。"
                session.close()
                return self.write(ret_msg(code=-1, error_message=msg))
            else:
                logger.info(
                    f"register: open_id={open_id} type={agency_type} sub_type={sub_type}"
                )
                if shop_type == 1:
                    # 商家
                    agency.ebf_agency_type = 3
                    agency.ebf_agency_sub_type = 1
                elif shop_type == 2:
                    # 行家
                    agency.ebf_agency_type = 3
                    agency.ebf_agency_sub_type = 2
                else:
                    # 新事业合伙人
                    pass

                user_id1 = "P" + str(agency_id)
                user_id2 = (
                    ("P" + agency.ebf_agency_contact)
                    if agency.ebf_agency_contact
                    else None
                )
                user_id3 = (
                    agency.ebf_agency_contact if agency.ebf_agency_contact else None
                )
                id_list = [user_id1, user_id2, user_id3]
                user = session.query(User).filter(User.ebf_user_id.in_(id_list)).first()
                if user:
                    user.ebf_user_headurl = logo_url

                agency.ebf_agency_name = store_name
                agency.ebf_agency_real_name = name
                agency.ebf_agency_profile = profile
                agency.ebf_agency_address = address
                agency.ebf_agency_contact = phone
                agency.ebf_agency_latitude = lat
                agency.ebf_agency_longitude = lng
                agency.ebf_agency_update_time = datetime.datetime.now()
                agency.ebf_agency_work_time = work_time
                if real_shop_id:
                    agency.ebf_agency_investor_id = real_shop_id  # 绑定门店挂靠关系
                session.commit()
                session.close()
                # 触发注册事件
                tasks.store_registered.delay(agency_id)
                return self.write(ret_msg())
        else:
            await self.add_agency(
                shop_type,
                open_id,
                inviter_oid,
                name,
                store_name,
                profile,
                address,
                phone,
                lat,
                lng,
                real_shop_id,
            )


class SendGoods(ApiBaseHandler):
    async def post(self):
        """
        通知发货（平台）
        :return:
        """
        order_id = self.get_parameter("order_id")
        express_number = self.get_parameter("courier_number", "")
        express_name = self.get_parameter("express_name", "")
        remarks = self.get_parameter("remarks", "")

        if not order_id:
            return self.write(ret_msg(code=-1, error_message="发货：没有订单号"))

        class Order(object):
            pass

        session = self.get_db_session([{"db_table": "sdet_order", "model": Order}])
        order = session.query(Order).filter_by(sdef_order_id=order_id).first()

        express_info = []
        if not re.match(r"^\s*$", express_number):
            express_info.append(
                dict(
                    express_number=express_number,
                    express_name=config.EXPRESS_LIST.get(express_name, "未知"),
                    express_symbol=express_name,
                )
            )

        # 保存快递名称、快递单号、备注
        if isinstance(express_info, list):
            courier_number = json.dumps(express_info)
            order.sdef_order_express_no = courier_number

        if remarks:
            order.sdef_order_remarks = remarks

        order.sdef_order_status = OrderStatus.WAIT_PICKUP
        session.commit()
        session.close()
        return self.write(ret_msg())


class OrderDeliveryNotification(ApiBaseHandler):
    async def get(self, order_id):
        """
        通知发货（平台调用通知供应商发货）
        :return:
        """

        if not order_id:
            return self.write(ret_msg(code=-1, error_message="发货：没有订单号"))

        # 通知供应商发货
        tasks.order_goods_wait_pickup.delay(order_id)
        return self.write(ret_msg())


class OrderShipped(ApiBaseHandler):
    async def post(self):
        """
        确认发货（供应商调用通知平台订单已发货）
        :return:
        """
        action = self.get_parameter("action")
        order_id = self.get_parameter("order_id")
        supplier_id = self.get_parameter("supplier_id", 0)
        remarks = self.get_parameter("remarks", "")

        if not order_id:
            return self.write(ret_msg(code=-1, error_message="请求参数错误"))
        if action != "confirm_order_shipped":
            return self.write(ret_msg(code=-1, error_message="请求参数错误"))

        class Order(object):
            pass

        session = self.get_db_session([{"db_table": "sdet_order", "model": Order}])
        order = session.query(Order).filter_by(sdef_order_id=order_id).first()
        if not order:
            session.close()
            logger.error(f"确认发货: 订单不存在！ order_id={order_id}")
            return self.finish(ret_msg(-1, error_message="订单不存在！"))

        order.sdef_order_status = OrderStatus.EXPRESSED

        if remarks:
            order.sdef_order_remarks += remarks
        session.commit()

        # 发货时调用确认发货接口，config天后自动确认收货
        if not add_mq_task(
            order_id,
            message_type=4,
            delay=DAYS_AFTER_SHIPPED_FOR_AUTO_COMPLETION * 24 * 3600,
        ):
            session.close()
            return self.finish(ret_msg(-1, error_message="确认发货失败"))

        tasks.order_goods_shipped.delay(order_id)  # 订单已发货
        session.close()
        return self.finish(ret_msg())


if __name__ == "__main__":
    pass